Skip to content

Commit

Permalink
[8.12] [Fleet] Fix 500 in Fleet API when request to product versions …
Browse files Browse the repository at this point in the history
…endpoint throws ECONNREFUSED (#172850) (#172865)

# Backport

This will backport the following commits from `main` to `8.12`:
- [[Fleet] Fix 500 in Fleet API when request to product versions
endpoint throws ECONNREFUSED
(#172850)](#172850)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Kyle
Pollich","email":"[email protected]"},"sourceCommit":{"committedDate":"2023-12-07T18:14:35Z","message":"[Fleet]
Fix 500 in Fleet API when request to product versions endpoint throws
ECONNREFUSED (#172850)\n\n## Summary\r\n\r\nNetwork-level errors will
cause `fetch` to `throw` rather than resolving\r\nwith a status code.
This PR updates our logic to handle this case for\r\nairgapped
environments where `ECONNREFUSED` style errors squash HTTP\r\nrequests
at the DNS
level.","sha":"be6fbc4dcc8fff7e7419cf3fa9b05a6b13e3edba","branchLabelMapping":{"^v8.13.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:Fleet","backport:prev-minor","v8.12.0","v8.13.0","v8.11.3"],"number":172850,"url":"https://github.com/elastic/kibana/pull/172850","mergeCommit":{"message":"[Fleet]
Fix 500 in Fleet API when request to product versions endpoint throws
ECONNREFUSED (#172850)\n\n## Summary\r\n\r\nNetwork-level errors will
cause `fetch` to `throw` rather than resolving\r\nwith a status code.
This PR updates our logic to handle this case for\r\nairgapped
environments where `ECONNREFUSED` style errors squash HTTP\r\nrequests
at the DNS
level.","sha":"be6fbc4dcc8fff7e7419cf3fa9b05a6b13e3edba"}},"sourceBranch":"main","suggestedTargetBranches":["8.12","8.11"],"targetPullRequestStates":[{"branch":"8.12","label":"v8.12.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.13.0","labelRegex":"^v8.13.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/172850","number":172850,"mergeCommit":{"message":"[Fleet]
Fix 500 in Fleet API when request to product versions endpoint throws
ECONNREFUSED (#172850)\n\n## Summary\r\n\r\nNetwork-level errors will
cause `fetch` to `throw` rather than resolving\r\nwith a status code.
This PR updates our logic to handle this case for\r\nairgapped
environments where `ECONNREFUSED` style errors squash HTTP\r\nrequests
at the DNS
level.","sha":"be6fbc4dcc8fff7e7419cf3fa9b05a6b13e3edba"}},{"branch":"8.11","label":"v8.11.3","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Kyle Pollich <[email protected]>
  • Loading branch information
kibanamachine and kpollich authored Dec 7, 2023
1 parent e5bcd5f commit c360cc9
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 14 deletions.
25 changes: 25 additions & 0 deletions x-pack/plugins/fleet/server/services/agents/versions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,29 @@ describe('getAvailableVersions', () => {
expect(mockedFetch).toBeCalledTimes(1);
expect(res2).not.toContain('300.0.0');
});

it('should gracefully handle 400 errors when fetching from product versions API', async () => {
mockKibanaVersion = '300.0.0';
mockedReadFile.mockResolvedValue(`["8.1.0", "8.0.0", "7.17.0", "7.16.0"]`);
mockedFetch.mockResolvedValue({
status: 400,
text: 'Bad request',
} as any);

const res = await getAvailableVersions({ ignoreCache: true });

// Should sort, uniquify and filter out versions < 7.17
expect(res).toEqual(['8.1.0', '8.0.0', '7.17.0']);
});

it('should gracefully handle network errors when fetching from product versions API', async () => {
mockKibanaVersion = '300.0.0';
mockedReadFile.mockResolvedValue(`["8.1.0", "8.0.0", "7.17.0", "7.16.0"]`);
mockedFetch.mockRejectedValue('ECONNREFUSED');

const res = await getAvailableVersions({ ignoreCache: true });

// Should sort, uniquify and filter out versions < 7.17
expect(res).toEqual(['8.1.0', '8.0.0', '7.17.0']);
});
});
37 changes: 23 additions & 14 deletions x-pack/plugins/fleet/server/services/agents/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const AGENT_VERSION_BUILD_FILE = 'x-pack/plugins/fleet/target/agent_versions_lis

// Endpoint maintained by the web-team and hosted on the elastic website
const PRODUCT_VERSIONS_URL = 'https://www.elastic.co/api/product_versions';
const MAX_REQUEST_TIMEOUT = 60 * 1000; // Only attempt to fetch product versions for one minute total

// Cache available versions in memory for 1 hour
const CACHE_DURATION = 1000 * 60 * 60;
Expand Down Expand Up @@ -118,21 +119,29 @@ async function fetchAgentVersionsFromApi() {
},
};

const response = await pRetry(() => fetch(PRODUCT_VERSIONS_URL, options), { retries: 1 });
const rawBody = await response.text();

// We need to handle non-200 responses gracefully here to support airgapped environments where
// Kibana doesn't have internet access to query this API
if (response.status >= 400) {
logger.debug(`Status code ${response.status} received from versions API: ${rawBody}`);
return [];
}
try {
const response = await pRetry(() => fetch(PRODUCT_VERSIONS_URL, options), {
retries: 1,
maxRetryTime: MAX_REQUEST_TIMEOUT,
});
const rawBody = await response.text();

// We need to handle non-200 responses gracefully here to support airgapped environments where
// Kibana doesn't have internet access to query this API
if (response.status >= 400) {
logger.debug(`Status code ${response.status} received from versions API: ${rawBody}`);
return [];
}

const jsonBody = JSON.parse(rawBody);
const jsonBody = JSON.parse(rawBody);

const versions: string[] = (jsonBody.length ? jsonBody[0] : [])
.filter((item: any) => item?.title?.includes('Elastic Agent'))
.map((item: any) => item?.version_number);
const versions: string[] = (jsonBody.length ? jsonBody[0] : [])
.filter((item: any) => item?.title?.includes('Elastic Agent'))
.map((item: any) => item?.version_number);

return versions;
return versions;
} catch (error) {
logger.debug(`Error fetching available versions from API: ${error.message}`);
return [];
}
}

0 comments on commit c360cc9

Please sign in to comment.