diff --git a/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.core.md b/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.core.md
index 3a5e84ffdc372..268dcdd77d6b4 100644
--- a/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.core.md
+++ b/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.core.md
@@ -11,8 +11,9 @@ core: {
savedObjects: {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
- exporter: ISavedObjectsExporter;
- importer: ISavedObjectsImporter;
+ getClient: (options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;
+ getExporter: (client: SavedObjectsClientContract) => ISavedObjectsExporter;
+ getImporter: (client: SavedObjectsClientContract) => ISavedObjectsImporter;
};
elasticsearch: {
client: IScopedClusterClient;
diff --git a/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md b/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md
index 5300c85cf9406..54d85910f823c 100644
--- a/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md
+++ b/docs/development/core/server/kibana-plugin-core-server.requesthandlercontext.md
@@ -18,5 +18,5 @@ export interface RequestHandlerContext
| Property | Type | Description |
| --- | --- | --- |
-| [core](./kibana-plugin-core-server.requesthandlercontext.core.md) | {
savedObjects: {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
exporter: ISavedObjectsExporter;
importer: ISavedObjectsImporter;
};
elasticsearch: {
client: IScopedClusterClient;
legacy: {
client: ILegacyScopedClusterClient;
};
};
uiSettings: {
client: IUiSettingsClient;
};
}
| |
+| [core](./kibana-plugin-core-server.requesthandlercontext.core.md) | {
savedObjects: {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
getClient: (options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;
getExporter: (client: SavedObjectsClientContract) => ISavedObjectsExporter;
getImporter: (client: SavedObjectsClientContract) => ISavedObjectsImporter;
};
elasticsearch: {
client: IScopedClusterClient;
legacy: {
client: ILegacyScopedClusterClient;
};
};
uiSettings: {
client: IUiSettingsClient;
};
}
| |
diff --git a/src/core/server/core_route_handler_context.ts b/src/core/server/core_route_handler_context.ts
index f3e06ad8f1daa..f5123a91e7100 100644
--- a/src/core/server/core_route_handler_context.ts
+++ b/src/core/server/core_route_handler_context.ts
@@ -13,8 +13,7 @@ import { SavedObjectsClientContract } from './saved_objects/types';
import {
InternalSavedObjectsServiceStart,
ISavedObjectTypeRegistry,
- ISavedObjectsExporter,
- ISavedObjectsImporter,
+ SavedObjectsClientProviderOptions,
} from './saved_objects';
import {
InternalElasticsearchServiceStart,
@@ -58,8 +57,6 @@ class CoreSavedObjectsRouteHandlerContext {
) {}
#scopedSavedObjectsClient?: SavedObjectsClientContract;
#typeRegistry?: ISavedObjectTypeRegistry;
- #exporter?: ISavedObjectsExporter;
- #importer?: ISavedObjectsImporter;
public get client() {
if (this.#scopedSavedObjectsClient == null) {
@@ -75,19 +72,18 @@ class CoreSavedObjectsRouteHandlerContext {
return this.#typeRegistry;
}
- public get exporter() {
- if (this.#exporter == null) {
- this.#exporter = this.savedObjectsStart.createExporter(this.client);
- }
- return this.#exporter;
- }
+ public getClient = (options?: SavedObjectsClientProviderOptions) => {
+ if (!options) return this.client;
+ return this.savedObjectsStart.getScopedClient(this.request, options);
+ };
- public get importer() {
- if (this.#importer == null) {
- this.#importer = this.savedObjectsStart.createImporter(this.client);
- }
- return this.#importer;
- }
+ public getExporter = (client: SavedObjectsClientContract) => {
+ return this.savedObjectsStart.createExporter(client);
+ };
+
+ public getImporter = (client: SavedObjectsClientContract) => {
+ return this.savedObjectsStart.createImporter(client);
+ };
}
class CoreUiSettingsRouteHandlerContext {
diff --git a/src/core/server/index.ts b/src/core/server/index.ts
index dac2d210eb395..8e4cdc7d59e32 100644
--- a/src/core/server/index.ts
+++ b/src/core/server/index.ts
@@ -49,6 +49,7 @@ import {
SavedObjectsServiceStart,
ISavedObjectsExporter,
ISavedObjectsImporter,
+ SavedObjectsClientProviderOptions,
} from './saved_objects';
import { CapabilitiesSetup, CapabilitiesStart } from './capabilities';
import { MetricsServiceSetup, MetricsServiceStart } from './metrics';
@@ -415,8 +416,9 @@ export interface RequestHandlerContext {
savedObjects: {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
- exporter: ISavedObjectsExporter;
- importer: ISavedObjectsImporter;
+ getClient: (options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;
+ getExporter: (client: SavedObjectsClientContract) => ISavedObjectsExporter;
+ getImporter: (client: SavedObjectsClientContract) => ISavedObjectsImporter;
};
elasticsearch: {
client: IScopedClusterClient;
diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts
index a4ce94b177612..19056ae1b9bc7 100644
--- a/src/core/server/mocks.ts
+++ b/src/core/server/mocks.ts
@@ -196,8 +196,9 @@ function createCoreRequestHandlerContextMock() {
savedObjects: {
client: savedObjectsClientMock.create(),
typeRegistry: savedObjectsTypeRegistryMock.create(),
- exporter: savedObjectsServiceMock.createExporter(),
- importer: savedObjectsServiceMock.createImporter(),
+ getClient: savedObjectsClientMock.create,
+ getExporter: savedObjectsServiceMock.createExporter,
+ getImporter: savedObjectsServiceMock.createImporter,
},
elasticsearch: {
client: elasticsearchServiceMock.createScopedClusterClient(),
diff --git a/src/core/server/saved_objects/routes/delete.ts b/src/core/server/saved_objects/routes/delete.ts
index 609ce2692c777..fe08acf23fd23 100644
--- a/src/core/server/saved_objects/routes/delete.ts
+++ b/src/core/server/saved_objects/routes/delete.ts
@@ -32,11 +32,13 @@ export const registerDeleteRoute = (router: IRouter, { coreUsageData }: RouteDep
catchAndReturnBoomErrors(async (context, req, res) => {
const { type, id } = req.params;
const { force } = req.query;
+ const { getClient } = context.core.savedObjects;
const usageStatsClient = coreUsageData.getClient();
usageStatsClient.incrementSavedObjectsDelete({ request: req }).catch(() => {});
- const result = await context.core.savedObjects.client.delete(type, id, { force });
+ const client = getClient();
+ const result = await client.delete(type, id, { force });
return res.ok({ body: result });
})
);
diff --git a/src/core/server/saved_objects/routes/export.ts b/src/core/server/saved_objects/routes/export.ts
index fa5517303f18f..e0293a4522fc1 100644
--- a/src/core/server/saved_objects/routes/export.ts
+++ b/src/core/server/saved_objects/routes/export.ts
@@ -165,9 +165,9 @@ export const registerExportRoute = (
},
catchAndReturnBoomErrors(async (context, req, res) => {
const cleaned = cleanOptions(req.body);
- const supportedTypes = context.core.savedObjects.typeRegistry
- .getImportableAndExportableTypes()
- .map((t) => t.name);
+ const { typeRegistry, getExporter, getClient } = context.core.savedObjects;
+ const supportedTypes = typeRegistry.getImportableAndExportableTypes().map((t) => t.name);
+
let options: EitherExportOptions;
try {
options = validateOptions(cleaned, {
@@ -181,7 +181,12 @@ export const registerExportRoute = (
});
}
- const exporter = context.core.savedObjects.exporter;
+ const includedHiddenTypes = supportedTypes.filter((supportedType) =>
+ typeRegistry.isHidden(supportedType)
+ );
+
+ const client = getClient({ includedHiddenTypes });
+ const exporter = getExporter(client);
const usageStatsClient = coreUsageData.getClient();
usageStatsClient
diff --git a/src/core/server/saved_objects/routes/import.ts b/src/core/server/saved_objects/routes/import.ts
index e84c638d3ec99..6f75bcf9fd5bf 100644
--- a/src/core/server/saved_objects/routes/import.ts
+++ b/src/core/server/saved_objects/routes/import.ts
@@ -63,6 +63,7 @@ export const registerImportRoute = (
},
catchAndReturnBoomErrors(async (context, req, res) => {
const { overwrite, createNewCopies } = req.query;
+ const { getClient, getImporter, typeRegistry } = context.core.savedObjects;
const usageStatsClient = coreUsageData.getClient();
usageStatsClient
@@ -84,7 +85,15 @@ export const registerImportRoute = (
});
}
- const { importer } = context.core.savedObjects;
+ const supportedTypes = typeRegistry.getImportableAndExportableTypes().map((t) => t.name);
+
+ const includedHiddenTypes = supportedTypes.filter((supportedType) =>
+ typeRegistry.isHidden(supportedType)
+ );
+
+ const client = getClient({ includedHiddenTypes });
+ const importer = getImporter(client);
+
try {
const result = await importer.import({
readStream,
diff --git a/src/core/server/saved_objects/routes/integration_tests/delete.test.ts b/src/core/server/saved_objects/routes/integration_tests/delete.test.ts
index 7b7a71b7ca858..eaec6e16cbd8c 100644
--- a/src/core/server/saved_objects/routes/integration_tests/delete.test.ts
+++ b/src/core/server/saved_objects/routes/integration_tests/delete.test.ts
@@ -26,7 +26,8 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => {
beforeEach(async () => {
({ server, httpSetup, handlerContext } = await setupServer());
- savedObjectsClient = handlerContext.savedObjects.client;
+ savedObjectsClient = handlerContext.savedObjects.getClient();
+ handlerContext.savedObjects.getClient = jest.fn().mockImplementation(() => savedObjectsClient);
const router = httpSetup.createRouter('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
diff --git a/src/core/server/saved_objects/routes/integration_tests/export.test.ts b/src/core/server/saved_objects/routes/integration_tests/export.test.ts
index 40f13064b53f0..09d475f29f362 100644
--- a/src/core/server/saved_objects/routes/integration_tests/export.test.ts
+++ b/src/core/server/saved_objects/routes/integration_tests/export.test.ts
@@ -40,9 +40,13 @@ describe('POST /api/saved_objects/_export', () => {
handlerContext.savedObjects.typeRegistry.getImportableAndExportableTypes.mockReturnValue(
allowedTypes.map(createExportableType)
);
- exporter = handlerContext.savedObjects.exporter;
+ exporter = handlerContext.savedObjects.getExporter();
const router = httpSetup.createRouter('/api/saved_objects/');
+ handlerContext.savedObjects.getExporter = jest
+ .fn()
+ .mockImplementation(() => exporter as ReturnType);
+
coreUsageStatsClient = coreUsageStatsClientMock.create();
coreUsageStatsClient.incrementSavedObjectsExport.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail
const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient);
@@ -77,6 +81,7 @@ describe('POST /api/saved_objects/_export', () => {
],
},
];
+
exporter.exportByTypes.mockResolvedValueOnce(createListStream(sortedObjects));
const result = await supertest(httpSetup.server.listener)
diff --git a/src/core/server/saved_objects/routes/integration_tests/import.test.ts b/src/core/server/saved_objects/routes/integration_tests/import.test.ts
index 24122c61c9f42..be4d2160a967b 100644
--- a/src/core/server/saved_objects/routes/integration_tests/import.test.ts
+++ b/src/core/server/saved_objects/routes/integration_tests/import.test.ts
@@ -68,9 +68,9 @@ describe(`POST ${URL}`, () => {
typeRegistry: handlerContext.savedObjects.typeRegistry,
importSizeLimit: 10000,
});
- handlerContext.savedObjects.importer.import.mockImplementation((options) =>
- importer.import(options)
- );
+ handlerContext.savedObjects.getImporter = jest
+ .fn()
+ .mockImplementation(() => importer as jest.Mocked);
const router = httpSetup.createRouter('/internal/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
diff --git a/src/core/server/saved_objects/routes/integration_tests/resolve_import_errors.test.ts b/src/core/server/saved_objects/routes/integration_tests/resolve_import_errors.test.ts
index b23211aef092f..d84b56156b543 100644
--- a/src/core/server/saved_objects/routes/integration_tests/resolve_import_errors.test.ts
+++ b/src/core/server/saved_objects/routes/integration_tests/resolve_import_errors.test.ts
@@ -66,7 +66,7 @@ describe(`POST ${URL}`, () => {
} as any)
);
- savedObjectsClient = handlerContext.savedObjects.client;
+ savedObjectsClient = handlerContext.savedObjects.getClient();
savedObjectsClient.checkConflicts.mockResolvedValue({ errors: [] });
const importer = new SavedObjectsImporter({
@@ -74,9 +74,10 @@ describe(`POST ${URL}`, () => {
typeRegistry: handlerContext.savedObjects.typeRegistry,
importSizeLimit: 10000,
});
- handlerContext.savedObjects.importer.resolveImportErrors.mockImplementation((options) =>
- importer.resolveImportErrors(options)
- );
+
+ handlerContext.savedObjects.getImporter = jest
+ .fn()
+ .mockImplementation(() => importer as jest.Mocked);
const router = httpSetup.createRouter('/api/saved_objects/');
coreUsageStatsClient = coreUsageStatsClientMock.create();
diff --git a/src/core/server/saved_objects/routes/resolve_import_errors.ts b/src/core/server/saved_objects/routes/resolve_import_errors.ts
index 2a664328d4df2..a05c7d30b91fd 100644
--- a/src/core/server/saved_objects/routes/resolve_import_errors.ts
+++ b/src/core/server/saved_objects/routes/resolve_import_errors.ts
@@ -9,6 +9,7 @@
import { extname } from 'path';
import { Readable } from 'stream';
import { schema } from '@kbn/config-schema';
+import { chain } from 'lodash';
import { IRouter } from '../../http';
import { CoreUsageDataSetup } from '../../core_usage_data';
import { SavedObjectConfig } from '../saved_objects_config';
@@ -91,7 +92,18 @@ export const registerResolveImportErrorsRoute = (
});
}
- const { importer } = context.core.savedObjects;
+ const { getClient, getImporter, typeRegistry } = context.core.savedObjects;
+
+ const includedHiddenTypes = chain(req.body.retries)
+ .map('type')
+ .uniq()
+ .filter(
+ (type) => typeRegistry.isHidden(type) && typeRegistry.isImportableAndExportable(type)
+ )
+ .value();
+
+ const client = getClient({ includedHiddenTypes });
+ const importer = getImporter(client);
try {
const result = await importer.resolveImportErrors({
diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md
index 34df3bcf85324..377cd2bc2068a 100644
--- a/src/core/server/server.api.md
+++ b/src/core/server/server.api.md
@@ -1924,8 +1924,9 @@ export interface RequestHandlerContext {
savedObjects: {
client: SavedObjectsClientContract;
typeRegistry: ISavedObjectTypeRegistry;
- exporter: ISavedObjectsExporter;
- importer: ISavedObjectsImporter;
+ getClient: (options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;
+ getExporter: (client: SavedObjectsClientContract) => ISavedObjectsExporter;
+ getImporter: (client: SavedObjectsClientContract) => ISavedObjectsImporter;
};
elasticsearch: {
client: IScopedClusterClient;
diff --git a/src/plugins/home/server/services/sample_data/routes/install.ts b/src/plugins/home/server/services/sample_data/routes/install.ts
index d32a854f2bc4b..7c00a46602e26 100644
--- a/src/plugins/home/server/services/sample_data/routes/install.ts
+++ b/src/plugins/home/server/services/sample_data/routes/install.ts
@@ -143,7 +143,15 @@ export function createInstallRoute(
let createResults;
try {
- createResults = await context.core.savedObjects.client.bulkCreate(
+ const { getClient, typeRegistry } = context.core.savedObjects;
+
+ const includedHiddenTypes = sampleDataset.savedObjects
+ .map((object) => object.type)
+ .filter((supportedType) => typeRegistry.isHidden(supportedType));
+
+ const client = getClient({ includedHiddenTypes });
+
+ createResults = await client.bulkCreate(
sampleDataset.savedObjects.map(({ version, ...savedObject }) => savedObject),
{ overwrite: true }
);
@@ -156,8 +164,8 @@ export function createInstallRoute(
return Boolean(savedObjectCreateResult.error);
});
if (errors.length > 0) {
- const errMsg = `sample_data install errors while loading saved objects. Errors: ${errors.join(
- ','
+ const errMsg = `sample_data install errors while loading saved objects. Errors: ${JSON.stringify(
+ errors
)}`;
logger.warn(errMsg);
return res.customError({ body: errMsg, statusCode: 403 });
diff --git a/src/plugins/home/server/services/sample_data/routes/uninstall.ts b/src/plugins/home/server/services/sample_data/routes/uninstall.ts
index 54e6fa0936abc..aa8ed67cf840a 100644
--- a/src/plugins/home/server/services/sample_data/routes/uninstall.ts
+++ b/src/plugins/home/server/services/sample_data/routes/uninstall.ts
@@ -33,7 +33,7 @@ export function createUninstallRoute(
client: { callAsCurrentUser },
},
},
- savedObjects: { client: savedObjectsClient },
+ savedObjects: { getClient: getSavedObjectsClient, typeRegistry },
},
},
request,
@@ -61,6 +61,12 @@ export function createUninstallRoute(
}
}
+ const includedHiddenTypes = sampleDataset.savedObjects
+ .map((object) => object.type)
+ .filter((supportedType) => typeRegistry.isHidden(supportedType));
+
+ const savedObjectsClient = getSavedObjectsClient({ includedHiddenTypes });
+
const deletePromises = sampleDataset.savedObjects.map(({ type, id }) =>
savedObjectsClient.delete(type, id)
);
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx
index b1570bb1fff0d..8b07351f6c2c2 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx
@@ -123,7 +123,10 @@ const CountIndicators: FC<{ importItems: ImportItem[] }> = ({ importItems }) =>
{errorCount && (
-
+