mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
# Backport This will backport the following commits from `main` to `8.18`: - [Connectors: Filter inference connectors without existing endpoints (#217641)](https://github.com/elastic/kibana/pull/217641) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Dima Arnautov","email":"dmitrii.arnautov@elastic.co"},"sourceCommit":{"committedDate":"2025-04-09T21:15:38Z","message":"Connectors: Filter inference connectors without existing endpoints (#217641)\n\n## Summary\n\nUpdated the `getAll` method in the actions client to exclude inference\nconnectors that lack inference endpoints.\n\n### Checklist\n\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"70c817db229dd6a9ea0485511b58b134b0d18bf4","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix",":ml","v9.0.0","Feature:Actions/ConnectorTypes","Team:ML","backport:version","v8.18.0","v9.1.0","v8.19.0","Feature:Inference UI"],"title":"Connectors: Filter inference connectors without existing endpoints ","number":217641,"url":"https://github.com/elastic/kibana/pull/217641","mergeCommit":{"message":"Connectors: Filter inference connectors without existing endpoints (#217641)\n\n## Summary\n\nUpdated the `getAll` method in the actions client to exclude inference\nconnectors that lack inference endpoints.\n\n### Checklist\n\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"70c817db229dd6a9ea0485511b58b134b0d18bf4"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.18","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/217641","number":217641,"mergeCommit":{"message":"Connectors: Filter inference connectors without existing endpoints (#217641)\n\n## Summary\n\nUpdated the `getAll` method in the actions client to exclude inference\nconnectors that lack inference endpoints.\n\n### Checklist\n\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"70c817db229dd6a9ea0485511b58b134b0d18bf4"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> --------- Co-authored-by: Dima Arnautov <dmitrii.arnautov@elastic.co> Co-authored-by: Quynh Nguyen <quynh.nguyen@elastic.co>
This commit is contained in:
parent
756177e7aa
commit
0159aab0ba
2 changed files with 125 additions and 9 deletions
|
@ -25,6 +25,7 @@ import { Logger } from '@kbn/logging';
|
|||
import { eventLogClientMock } from '@kbn/event-log-plugin/server/event_log_client.mock';
|
||||
import { ActionTypeRegistry } from '../../../../action_type_registry';
|
||||
import { getAllUnsecured } from './get_all';
|
||||
import type { InferenceInferenceEndpointInfo } from '@elastic/elasticsearch/lib/api/types';
|
||||
|
||||
jest.mock('@kbn/core-saved-objects-utils-server', () => {
|
||||
const actual = jest.requireActual('@kbn/core-saved-objects-utils-server');
|
||||
|
@ -611,6 +612,85 @@ describe('getAll()', () => {
|
|||
|
||||
expect(logger.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('filters out inference connectors without endpoints', async () => {
|
||||
unsecuredSavedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1,
|
||||
per_page: 10,
|
||||
page: 1,
|
||||
saved_objects: [],
|
||||
});
|
||||
|
||||
scopedClusterClient.asInternalUser.search.mockResponse(
|
||||
// @ts-expect-error not full search response
|
||||
{
|
||||
aggregations: {
|
||||
testPreconfigured01: { doc_count: 2 },
|
||||
testPreconfigured02: { doc_count: 2 },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
scopedClusterClient.asInternalUser.inference.get.mockResolvedValueOnce({
|
||||
endpoints: [{ inference_id: '2' } as InferenceInferenceEndpointInfo],
|
||||
});
|
||||
|
||||
actionsClient = new ActionsClient({
|
||||
logger,
|
||||
actionTypeRegistry,
|
||||
unsecuredSavedObjectsClient,
|
||||
ephemeralExecutionEnqueuer,
|
||||
scopedClusterClient,
|
||||
kibanaIndices,
|
||||
actionExecutor,
|
||||
bulkExecutionEnqueuer,
|
||||
request,
|
||||
authorization: authorization as unknown as ActionsAuthorization,
|
||||
inMemoryConnectors: [
|
||||
{
|
||||
id: 'testPreconfigured01',
|
||||
actionTypeId: '.inference',
|
||||
name: 'test1',
|
||||
config: {
|
||||
inferenceId: '1',
|
||||
},
|
||||
secrets: {},
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
},
|
||||
{
|
||||
id: 'testPreconfigured02',
|
||||
actionTypeId: '.inference',
|
||||
name: 'test2',
|
||||
config: {
|
||||
inferenceId: '2',
|
||||
},
|
||||
secrets: {},
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
},
|
||||
],
|
||||
connectorTokenClient: connectorTokenClientMock.create(),
|
||||
getEventLogClient,
|
||||
});
|
||||
|
||||
const result = await actionsClient.getAll({ includeSystemActions: true });
|
||||
expect(result).toEqual([
|
||||
{
|
||||
actionTypeId: '.inference',
|
||||
id: 'testPreconfigured02',
|
||||
isDeprecated: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
name: 'test2',
|
||||
referencedByCount: 2,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAllSystemConnectors()', () => {
|
||||
|
|
|
@ -113,15 +113,17 @@ async function getAllHelper({
|
|||
|
||||
const mergedResult = [
|
||||
...savedObjectsActions,
|
||||
...inMemoryConnectors.map((inMemoryConnector) => ({
|
||||
id: inMemoryConnector.id,
|
||||
actionTypeId: inMemoryConnector.actionTypeId,
|
||||
name: inMemoryConnector.name,
|
||||
isPreconfigured: inMemoryConnector.isPreconfigured,
|
||||
isDeprecated: isConnectorDeprecated(inMemoryConnector),
|
||||
isSystemAction: inMemoryConnector.isSystemAction,
|
||||
...(inMemoryConnector.exposeConfig ? { config: inMemoryConnector.config } : {}),
|
||||
})),
|
||||
...(await filterInferenceConnectors(esClient, inMemoryConnectors)).map((connector) => {
|
||||
return {
|
||||
id: connector.id,
|
||||
actionTypeId: connector.actionTypeId,
|
||||
name: connector.name,
|
||||
isPreconfigured: connector.isPreconfigured,
|
||||
isDeprecated: isConnectorDeprecated(connector),
|
||||
isSystemAction: connector.isSystemAction,
|
||||
...(connector.exposeConfig ? { config: connector.config } : {}),
|
||||
};
|
||||
}),
|
||||
].sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
const connectors = await injectExtraFindData({
|
||||
|
@ -238,3 +240,37 @@ async function injectExtraFindData({
|
|||
referencedByCount: aggregationResult.aggregations[connector.id].doc_count,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out inference connectors that do not have an endpoint.
|
||||
* It requires a connector config in order to retrieve the inference id.
|
||||
*
|
||||
* @param esClient
|
||||
* @param connectors
|
||||
* @returns
|
||||
*/
|
||||
export async function filterInferenceConnectors(
|
||||
esClient: ElasticsearchClient,
|
||||
connectors: InMemoryConnector[]
|
||||
): Promise<InMemoryConnector[]> {
|
||||
let result = connectors;
|
||||
|
||||
if (result.some((connector) => connector.actionTypeId === '.inference')) {
|
||||
try {
|
||||
// Get all inference endpoints to filter out inference connector without endpoints
|
||||
const inferenceEndpoints = await esClient.inference.get();
|
||||
result = result.filter((connector) => {
|
||||
if (connector.actionTypeId !== '.inference') return true;
|
||||
|
||||
const inferenceEndpoint = inferenceEndpoints.endpoints.find(
|
||||
(endpoint) => endpoint.inference_id === connector.config?.inferenceId
|
||||
);
|
||||
return inferenceEndpoint !== undefined;
|
||||
});
|
||||
} catch (e) {
|
||||
// If we can't get the inference endpoints, we just return all connectors
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue