Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search across spaces #67644

Merged
merged 29 commits into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
36dd1b4
Allow saved objects to be searched across spaces
legrego Apr 20, 2020
bdb5110
Merge branch 'master' of github.com:elastic/kibana into spaces/search…
legrego Jun 16, 2020
10d4a2a
Start to address first round of feedback
legrego Jun 16, 2020
fa7b57d
Update x-pack/test/saved_object_api_integration/common/suites/find.ts
legrego Jun 17, 2020
602d8ff
Attempting option 3: wildcard is default namespace
legrego Jun 17, 2020
7e26c10
Merge branch 'spaces/search-across-spaces' of github.com:legrego/kiba…
legrego Jun 17, 2020
b0b2d95
Remove namespaces from common test cases
legrego Jun 17, 2020
8eb6bd3
fix type check
legrego Jun 17, 2020
7e50abf
omit namespaces from the export operation
legrego Jun 18, 2020
1ec9e7e
Merge branch 'master' of github.com:elastic/kibana into spaces/search…
legrego Jun 18, 2020
47e5e5e
fix types
legrego Jun 18, 2020
a9f7be0
Merge branch 'master' of github.com:elastic/kibana into spaces/search…
legrego Jun 23, 2020
eafbd10
fix mocked find result
legrego Jun 23, 2020
485f4b5
fix export api test
legrego Jun 23, 2020
5fbbf42
update find test
legrego Jun 24, 2020
0421c1a
Merge branch 'master' into spaces/search-across-spaces
elasticmachine Jun 24, 2020
d5796a8
start addressing feedback
legrego Jun 29, 2020
b6d2799
Merge branch 'spaces/search-across-spaces' of github.com:legrego/kiba…
legrego Jun 29, 2020
f1b8fc8
fixing repository test
legrego Jun 30, 2020
9f16270
Merge branch 'master' of github.com:elastic/kibana into spaces/search…
legrego Jun 30, 2020
078d3b7
simplify bulkCreate
legrego Jul 2, 2020
588f54b
Merge branch 'master' of github.com:elastic/kibana into spaces/search…
legrego Jul 2, 2020
793dc76
start addressing platform feedback
legrego Jul 2, 2020
effc986
Merge branch 'master' into spaces/search-across-spaces
elasticmachine Jul 2, 2020
0f50101
Merge branch 'master' of github.com:elastic/kibana into spaces/search…
legrego Jul 8, 2020
3f6c1bf
changing order of saved objects authorization checks
legrego Jul 8, 2020
6c2df02
Merge branch 'spaces/search-across-spaces' of github.com:legrego/kiba…
legrego Jul 8, 2020
7a095e8
address platform PR feedback
legrego Jul 13, 2020
c134749
Merge branch 'master' of github.com:elastic/kibana into spaces/search…
legrego Jul 13, 2020
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 @@ -8,7 +8,7 @@
<b>Signature:</b>

```typescript
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
export interface SavedObjectsFindOptions
```

## Properties
Expand All @@ -19,6 +19,7 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
| [fields](./kibana-plugin-core-public.savedobjectsfindoptions.fields.md) | <code>string[]</code> | An array of fields to include in the results |
| [filter](./kibana-plugin-core-public.savedobjectsfindoptions.filter.md) | <code>string</code> | |
| [hasReference](./kibana-plugin-core-public.savedobjectsfindoptions.hasreference.md) | <code>{</code><br/><code> type: string;</code><br/><code> id: string;</code><br/><code> }</code> | |
| [namespaces](./kibana-plugin-core-public.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
| [page](./kibana-plugin-core-public.savedobjectsfindoptions.page.md) | <code>number</code> | |
| [perPage](./kibana-plugin-core-public.savedobjectsfindoptions.perpage.md) | <code>number</code> | |
| [preference](./kibana-plugin-core-public.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-public](./kibana-plugin-core-public.md) &gt; [SavedObjectsFindOptions](./kibana-plugin-core-public.savedobjectsfindoptions.md) &gt; [namespaces](./kibana-plugin-core-public.savedobjectsfindoptions.namespaces.md)

## SavedObjectsFindOptions.namespaces property

<b>Signature:</b>

```typescript
namespaces?: string[];
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<b>Signature:</b>

```typescript
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
export interface SavedObjectsFindOptions
```

## Properties
Expand All @@ -19,6 +19,7 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions
| [fields](./kibana-plugin-core-server.savedobjectsfindoptions.fields.md) | <code>string[]</code> | An array of fields to include in the results |
| [filter](./kibana-plugin-core-server.savedobjectsfindoptions.filter.md) | <code>string</code> | |
| [hasReference](./kibana-plugin-core-server.savedobjectsfindoptions.hasreference.md) | <code>{</code><br/><code> type: string;</code><br/><code> id: string;</code><br/><code> }</code> | |
| [namespaces](./kibana-plugin-core-server.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
| [page](./kibana-plugin-core-server.savedobjectsfindoptions.page.md) | <code>number</code> | |
| [perPage](./kibana-plugin-core-server.savedobjectsfindoptions.perpage.md) | <code>number</code> | |
| [preference](./kibana-plugin-core-server.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsFindOptions](./kibana-plugin-core-server.savedobjectsfindoptions.md) &gt; [namespaces](./kibana-plugin-core-server.savedobjectsfindoptions.namespaces.md)

## SavedObjectsFindOptions.namespaces property

<b>Signature:</b>

```typescript
namespaces?: string[];
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
<b>Signature:</b>

```typescript
find<T = unknown>({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, }: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
find<T = unknown>({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, }: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| { search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, } | <code>SavedObjectsFindOptions</code> | |
| { search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, } | <code>SavedObjectsFindOptions</code> | |

<b>Returns:</b>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export declare class SavedObjectsRepository
| [delete(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.delete.md) | | Deletes an object |
| [deleteByNamespace(namespace, options)](./kibana-plugin-core-server.savedobjectsrepository.deletebynamespace.md) | | Deletes all objects from the provided namespace. |
| [deleteFromNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsrepository.deletefromnamespaces.md) | | Removes one or more namespaces from a given multi-namespace saved object. If no namespaces remain, the saved object is deleted entirely. This method and \[<code>addToNamespaces</code>\][SavedObjectsRepository.addToNamespaces()](./kibana-plugin-core-server.savedobjectsrepository.addtonamespaces.md) are the only ways to change which Spaces a multi-namespace saved object is shared to. |
| [find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespace, type, filter, preference, })](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | |
| [find({ search, defaultSearchOperator, searchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, })](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | |
| [get(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.get.md) | | Gets a single object |
| [incrementCounter(type, id, counterFieldName, options)](./kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md) | | Increases a counter field by one. Creates the document if one doesn't exist for the given id. |
| [update(type, id, attributes, options)](./kibana-plugin-core-server.savedobjectsrepository.update.md) | | Updates an object |
Expand Down
4 changes: 3 additions & 1 deletion src/core/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1282,7 +1282,7 @@ export interface SavedObjectsCreateOptions {
}

// @public (undocumented)
export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions {
export interface SavedObjectsFindOptions {
// (undocumented)
defaultSearchOperator?: 'AND' | 'OR';
fields?: string[];
Expand All @@ -1294,6 +1294,8 @@ export interface SavedObjectsFindOptions extends SavedObjectsBaseOptions {
id: string;
};
// (undocumented)
namespaces?: string[];
// (undocumented)
page?: number;
// (undocumented)
perPage?: number;
Expand Down
1 change: 1 addition & 0 deletions src/core/public/saved_objects/saved_objects_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ export class SavedObjectsClient {
sortField: 'sort_field',
type: 'type',
filter: 'filter',
namespaces: 'namespaces',
preference: 'preference',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,97 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": undefined,
"namespaces": undefined,
"perPage": 500,
"search": undefined,
"type": Array [
"index-pattern",
"search",
],
},
],
],
"results": Array [
Object {
"type": "return",
"value": Promise {},
},
],
}
`);
});

test('omits the `namespaces` property from the export', async () => {
savedObjectsClient.find.mockResolvedValueOnce({
total: 2,
saved_objects: [
{
id: '2',
type: 'search',
attributes: {},
namespaces: ['foo', 'bar'],
score: 0,
references: [
{
name: 'name',
type: 'index-pattern',
id: '1',
},
],
},
{
id: '1',
type: 'index-pattern',
attributes: {},
namespaces: ['foo', 'bar'],
score: 0,
references: [],
},
],
per_page: 1,
page: 0,
});
const exportStream = await exportSavedObjectsToStream({
savedObjectsClient,
exportSizeLimit: 500,
types: ['index-pattern', 'search'],
});

const response = await readStreamToCompletion(exportStream);

expect(response).toMatchInlineSnapshot(`
Array [
Object {
"attributes": Object {},
"id": "1",
"references": Array [],
"type": "index-pattern",
},
Object {
"attributes": Object {},
"id": "2",
"references": Array [
Object {
"id": "1",
"name": "name",
"type": "index-pattern",
},
],
"type": "search",
},
Object {
"exportedCount": 2,
"missingRefCount": 0,
"missingReferences": Array [],
},
]
`);
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
[MockFunction] {
"calls": Array [
Array [
Object {
"namespaces": undefined,
"perPage": 500,
"search": undefined,
"type": Array [
Expand Down Expand Up @@ -257,7 +347,7 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": undefined,
"namespaces": undefined,
"perPage": 500,
"search": "foo",
"type": Array [
Expand Down Expand Up @@ -346,7 +436,9 @@ describe('getSortedObjectsForExport()', () => {
"calls": Array [
Array [
Object {
"namespace": "foo",
"namespaces": Array [
"foo",
],
"perPage": 500,
"search": undefined,
"type": Array [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ async function fetchObjectsToExport({
type: types,
search,
perPage: exportSizeLimit,
namespace,
namespaces: namespace ? [namespace] : undefined,
rudolf marked this conversation as resolved.
Show resolved Hide resolved
});
if (findResponse.total > exportSizeLimit) {
throw Boom.badRequest(`Can't export more than ${exportSizeLimit} objects`);
Expand Down Expand Up @@ -162,10 +162,15 @@ export async function exportSavedObjectsToStream({
exportedObjects = sortObjects(rootObjects);
}

// redact attributes that should not be exported
const redactedObjects = exportedObjects.map<SavedObject<unknown>>(
({ namespaces, ...object }) => object
);
legrego marked this conversation as resolved.
Show resolved Hide resolved

const exportDetails: SavedObjectsExportResultDetails = {
exportedCount: exportedObjects.length,
missingRefCount: missingReferences.length,
missingReferences,
};
return createListStream([...exportedObjects, ...(excludeExportDetails ? [] : [exportDetails])]);
return createListStream([...redactedObjects, ...(excludeExportDetails ? [] : [exportDetails])]);
}
8 changes: 8 additions & 0 deletions src/core/server/saved_objects/routes/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,18 @@ export const registerFindRoute = (router: IRouter) => {
),
fields: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),
filter: schema.maybe(schema.string()),
namespaces: schema.maybe(
schema.oneOf([schema.string(), schema.arrayOf(schema.string())])
),
}),
},
},
router.handleLegacyErrors(async (context, req, res) => {
const query = req.query;

const namespaces =
typeof req.query.namespaces === 'string' ? [req.query.namespaces] : req.query.namespaces;

const result = await context.core.savedObjects.client.find({
perPage: query.per_page,
page: query.page,
Expand All @@ -62,6 +69,7 @@ export const registerFindRoute = (router: IRouter) => {
hasReference: query.has_reference,
fields: typeof query.fields === 'string' ? [query.fields] : query.fields,
filter: query.filter,
namespaces,
});

return res.ok({ body: result });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ describe('GET /api/saved_objects/_find', () => {
attributes: {},
score: 1,
references: [],
namespaces: ['default'],
},
{
type: 'index-pattern',
Expand All @@ -91,6 +92,7 @@ describe('GET /api/saved_objects/_find', () => {
attributes: {},
score: 1,
references: [],
namespaces: ['default'],
},
],
};
Expand Down Expand Up @@ -241,4 +243,38 @@ describe('GET /api/saved_objects/_find', () => {
defaultSearchOperator: 'OR',
});
});

it('accepts the query parameter namespaces as a string', async () => {
await supertest(httpSetup.server.listener)
.get('/api/saved_objects/_find?type=index-pattern&namespaces=foo')
.expect(200);

expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);

const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['index-pattern'],
namespaces: ['foo'],
defaultSearchOperator: 'OR',
});
});

it('accepts the query parameter namespaces as an array', async () => {
await supertest(httpSetup.server.listener)
.get('/api/saved_objects/_find?type=index-pattern&namespaces=default&namespaces=foo')
.expect(200);

expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);

const options = savedObjectsClient.find.mock.calls[0][0];
expect(options).toEqual({
perPage: 20,
page: 1,
type: ['index-pattern'],
namespaces: ['default', 'foo'],
defaultSearchOperator: 'OR',
});
});
});
Loading