Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type { Logger } from '@kbn/logging';
import { eventLogClientMock } from '@kbn/event-log-plugin/server/event_log_client.mock';
import type { 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');
Expand Down Expand Up @@ -585,6 +586,84 @@ 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,
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()', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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;
}