Skip to content

Commit

Permalink
Merge branch 'master' into reporting/switch-to-tm-pre
Browse files Browse the repository at this point in the history
  • Loading branch information
tsullivan committed Sep 22, 2020
2 parents 165734a + 311805a commit f8b449f
Show file tree
Hide file tree
Showing 62 changed files with 1,471 additions and 577 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export interface SavedObjectsFindOptions
| [sortField](./kibana-plugin-core-public.savedobjectsfindoptions.sortfield.md) | <code>string</code> | |
| [sortOrder](./kibana-plugin-core-public.savedobjectsfindoptions.sortorder.md) | <code>string</code> | |
| [type](./kibana-plugin-core-public.savedobjectsfindoptions.type.md) | <code>string &#124; string[]</code> | |
| [typeToNamespacesMap](./kibana-plugin-core-public.savedobjectsfindoptions.typetonamespacesmap.md) | <code>Map&lt;string, string[] &#124; undefined&gt;</code> | This map defines each type to search for, and the namespace(s) to search for the type in; this is only intended to be used by a saved object client wrapper. If this is defined, it supersedes the <code>type</code> and <code>namespaces</code> fields when building the Elasticsearch query. Any types that are not included in this map will be excluded entirely. If a type is included but its value is undefined, the operation will search for that type in the Default namespace. |

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- 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; [typeToNamespacesMap](./kibana-plugin-core-public.savedobjectsfindoptions.typetonamespacesmap.md)

## SavedObjectsFindOptions.typeToNamespacesMap property

This map defines each type to search for, and the namespace(s) to search for the type in; this is only intended to be used by a saved object client wrapper. If this is defined, it supersedes the `type` and `namespaces` fields when building the Elasticsearch query. Any types that are not included in this map will be excluded entirely. If a type is included but its value is undefined, the operation will search for that type in the Default namespace.

<b>Signature:</b>

```typescript
typeToNamespacesMap?: Map<string, string[] | undefined>;
```
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export interface SavedObjectsFindOptions
| [sortField](./kibana-plugin-core-server.savedobjectsfindoptions.sortfield.md) | <code>string</code> | |
| [sortOrder](./kibana-plugin-core-server.savedobjectsfindoptions.sortorder.md) | <code>string</code> | |
| [type](./kibana-plugin-core-server.savedobjectsfindoptions.type.md) | <code>string &#124; string[]</code> | |
| [typeToNamespacesMap](./kibana-plugin-core-server.savedobjectsfindoptions.typetonamespacesmap.md) | <code>Map&lt;string, string[] &#124; undefined&gt;</code> | This map defines each type to search for, and the namespace(s) to search for the type in; this is only intended to be used by a saved object client wrapper. If this is defined, it supersedes the <code>type</code> and <code>namespaces</code> fields when building the Elasticsearch query. Any types that are not included in this map will be excluded entirely. If a type is included but its value is undefined, the operation will search for that type in the Default namespace. |

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- 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; [typeToNamespacesMap](./kibana-plugin-core-server.savedobjectsfindoptions.typetonamespacesmap.md)

## SavedObjectsFindOptions.typeToNamespacesMap property

This map defines each type to search for, and the namespace(s) to search for the type in; this is only intended to be used by a saved object client wrapper. If this is defined, it supersedes the `type` and `namespaces` fields when building the Elasticsearch query. Any types that are not included in this map will be excluded entirely. If a type is included but its value is undefined, the operation will search for that type in the Default namespace.

<b>Signature:</b>

```typescript
typeToNamespacesMap?: Map<string, string[] | undefined>;
```
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, rootSearchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, }: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
find<T = unknown>(options: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| { search, defaultSearchOperator, searchFields, rootSearchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, } | <code>SavedObjectsFindOptions</code> | |
| options | <code>SavedObjectsFindOptions</code> | |
<b>Returns:</b>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,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, rootSearchFields, hasReference, page, perPage, sortField, sortOrder, fields, namespaces, type, filter, preference, })](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | |
| [find(options)](./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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- 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; [SavedObjectsUtils](./kibana-plugin-core-server.savedobjectsutils.md) &gt; [createEmptyFindResponse](./kibana-plugin-core-server.savedobjectsutils.createemptyfindresponse.md)

## SavedObjectsUtils.createEmptyFindResponse property

Creates an empty response for a find operation. This is only intended to be used by saved objects client wrappers.

<b>Signature:</b>

```typescript
static createEmptyFindResponse: <T>({ page, perPage, }: SavedObjectsFindOptions) => SavedObjectsFindResponse<T>;
```
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export declare class SavedObjectsUtils

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [createEmptyFindResponse](./kibana-plugin-core-server.savedobjectsutils.createemptyfindresponse.md) | <code>static</code> | <code>&lt;T&gt;({ page, perPage, }: SavedObjectsFindOptions) =&gt; SavedObjectsFindResponse&lt;T&gt;</code> | Creates an empty response for a find operation. This is only intended to be used by saved objects client wrappers. |
| [namespaceIdToString](./kibana-plugin-core-server.savedobjectsutils.namespaceidtostring.md) | <code>static</code> | <code>(namespace?: string &#124; undefined) =&gt; string</code> | Converts a given saved object namespace ID to its string representation. All namespace IDs have an identical string representation, with the exception of the <code>undefined</code> namespace ID (which has a namespace string of <code>'default'</code>). |
| [namespaceStringToId](./kibana-plugin-core-server.savedobjectsutils.namespacestringtoid.md) | <code>static</code> | <code>(namespace: string) =&gt; string &#124; undefined</code> | Converts a given saved object namespace string to its ID representation. All namespace strings have an identical ID representation, with the exception of the <code>'default'</code> namespace string (which has a namespace ID of <code>undefined</code>). |

14 changes: 10 additions & 4 deletions docs/user/monitoring/viewing-metrics.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ At a minimum, you must have monitoring data for the {es} production cluster.
Once that data exists, {kib} can display monitoring data for other products in
the cluster.

TIP: If you use a separate monitoring cluster to store the monitoring data, it
is strongly recommended that you use a separate {kib} instance to view it. If
you log in to {kib} using SAML, Kerberos, PKI, OpenID Connect, or token
authentication providers, a dedicated {kib} instance is *required*. The security
tokens that are used in these contexts are cluster-specific, therefore you
cannot use a single {kib} instance to connect to both production and monitoring
clusters. For more information about the recommended configuration, see
{ref}/monitoring-overview.html[Monitoring overview].

. Identify where to retrieve monitoring data from.
+
--
The cluster that contains the monitoring data is referred to
as the _monitoring cluster_.

TIP: If the monitoring data is stored on a *dedicated* monitoring cluster, it is
If the monitoring data is stored on a dedicated monitoring cluster, it is
accessible even when the cluster you're monitoring is not. If you have at least
a gold license, you can send data from multiple clusters to the same monitoring
cluster and view them all through the same instance of {kib}.
Expand Down
1 change: 1 addition & 0 deletions src/core/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,7 @@ export interface SavedObjectsFindOptions {
sortOrder?: string;
// (undocumented)
type: string | string[];
typeToNamespacesMap?: Map<string, string[] | undefined>;
}

// @public
Expand Down
2 changes: 1 addition & 1 deletion src/core/public/saved_objects/saved_objects_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { HttpFetchOptions, HttpSetup } from '../http';

type SavedObjectsFindOptions = Omit<
SavedObjectFindOptionsServer,
'namespace' | 'sortOrder' | 'rootSearchFields'
'sortOrder' | 'rootSearchFields' | 'typeToNamespacesMap'
>;

type PromiseType<T extends Promise<any>> = T extends Promise<infer U> ? U : never;
Expand Down
93 changes: 76 additions & 17 deletions src/core/server/saved_objects/service/lib/repository.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2477,6 +2477,33 @@ describe('SavedObjectsRepository', () => {
expect(client.search).not.toHaveBeenCalled();
});

it(`throws when namespaces is an empty array`, async () => {
await expect(
savedObjectsRepository.find({ type: 'foo', namespaces: [] })
).rejects.toThrowError('options.namespaces cannot be an empty array');
expect(client.search).not.toHaveBeenCalled();
});

it(`throws when type is not falsy and typeToNamespacesMap is defined`, async () => {
await expect(
savedObjectsRepository.find({ type: 'foo', typeToNamespacesMap: new Map() })
).rejects.toThrowError(
'options.type must be an empty string when options.typeToNamespacesMap is used'
);
expect(client.search).not.toHaveBeenCalled();
});

it(`throws when type is not an empty array and typeToNamespacesMap is defined`, async () => {
const test = async (args) => {
await expect(savedObjectsRepository.find(args)).rejects.toThrowError(
'options.namespaces must be an empty array when options.typeToNamespacesMap is used'
);
expect(client.search).not.toHaveBeenCalled();
};
await test({ type: '', typeToNamespacesMap: new Map() });
await test({ type: '', namespaces: ['some-ns'], typeToNamespacesMap: new Map() });
});

it(`throws when searchFields is defined but not an array`, async () => {
await expect(
savedObjectsRepository.find({ type, searchFields: 'string' })
Expand All @@ -2493,7 +2520,7 @@ describe('SavedObjectsRepository', () => {

it(`throws when KQL filter syntax is invalid`, async () => {
const findOpts = {
namespace,
namespaces: [namespace],
search: 'foo*',
searchFields: ['foo'],
type: ['dashboard'],
Expand Down Expand Up @@ -2577,38 +2604,70 @@ describe('SavedObjectsRepository', () => {
const test = async (types) => {
const result = await savedObjectsRepository.find({ type: types });
expect(result).toEqual(expect.objectContaining({ saved_objects: [] }));
expect(client.search).not.toHaveBeenCalled();
};

await test('unknownType');
await test(HIDDEN_TYPE);
await test(['unknownType', HIDDEN_TYPE]);
});

it(`should return empty results when attempting to find only invalid or hidden types using typeToNamespacesMap`, async () => {
const test = async (types) => {
const result = await savedObjectsRepository.find({
typeToNamespacesMap: new Map(types.map((x) => [x, undefined])),
type: '',
namespaces: [],
});
expect(result).toEqual(expect.objectContaining({ saved_objects: [] }));
expect(client.search).not.toHaveBeenCalled();
};

await test(['unknownType']);
await test([HIDDEN_TYPE]);
await test(['unknownType', HIDDEN_TYPE]);
});
});

describe('search dsl', () => {
it(`passes mappings, registry, search, defaultSearchOperator, searchFields, type, sortField, sortOrder and hasReference to getSearchDsl`, async () => {
const commonOptions = {
type: [type], // cannot be used when `typeToNamespacesMap` is present
namespaces: [namespace], // cannot be used when `typeToNamespacesMap` is present
search: 'foo*',
searchFields: ['foo'],
sortField: 'name',
sortOrder: 'desc',
defaultSearchOperator: 'AND',
hasReference: {
type: 'foo',
id: '1',
},
kueryNode: undefined,
};

it(`passes mappings, registry, and search options to getSearchDsl`, async () => {
await findSuccess(commonOptions, namespace);
expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, registry, commonOptions);
});

it(`accepts typeToNamespacesMap`, async () => {
const relevantOpts = {
namespaces: [namespace],
search: 'foo*',
searchFields: ['foo'],
type: [type],
sortField: 'name',
sortOrder: 'desc',
defaultSearchOperator: 'AND',
hasReference: {
type: 'foo',
id: '1',
},
kueryNode: undefined,
...commonOptions,
type: '',
namespaces: [],
typeToNamespacesMap: new Map([[type, [namespace]]]), // can only be used when `type` is falsy and `namespaces` is an empty array
};

await findSuccess(relevantOpts, namespace);
expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, registry, relevantOpts);
expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, registry, {
...relevantOpts,
type: [type],
});
});

it(`accepts KQL expression filter and passes KueryNode to getSearchDsl`, async () => {
const findOpts = {
namespace,
namespaces: [namespace],
search: 'foo*',
searchFields: ['foo'],
type: ['dashboard'],
Expand Down Expand Up @@ -2649,7 +2708,7 @@ describe('SavedObjectsRepository', () => {

it(`accepts KQL KueryNode filter and passes KueryNode to getSearchDsl`, async () => {
const findOpts = {
namespace,
namespaces: [namespace],
search: 'foo*',
searchFields: ['foo'],
type: ['dashboard'],
Expand Down
65 changes: 40 additions & 25 deletions src/core/server/saved_objects/service/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import {
} from '../../types';
import { SavedObjectTypeRegistry } from '../../saved_objects_type_registry';
import { validateConvertFilterToKueryNode } from './filter_utils';
import { SavedObjectsUtils } from './utils';
import { FIND_DEFAULT_PAGE, FIND_DEFAULT_PER_PAGE, SavedObjectsUtils } from './utils';

// BEWARE: The SavedObjectClient depends on the implementation details of the SavedObjectsRepository
// so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient.
Expand Down Expand Up @@ -693,37 +693,51 @@ export class SavedObjectsRepository {
* @property {string} [options.preference]
* @returns {promise} - { saved_objects: [{ id, type, version, attributes }], total, per_page, page }
*/
async find<T = unknown>({
search,
defaultSearchOperator = 'OR',
searchFields,
rootSearchFields,
hasReference,
page = 1,
perPage = 20,
sortField,
sortOrder,
fields,
namespaces,
type,
filter,
preference,
}: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>> {
if (!type) {
async find<T = unknown>(options: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>> {
const {
search,
defaultSearchOperator = 'OR',
searchFields,
rootSearchFields,
hasReference,
page = FIND_DEFAULT_PAGE,
perPage = FIND_DEFAULT_PER_PAGE,
sortField,
sortOrder,
fields,
namespaces,
type,
typeToNamespacesMap,
filter,
preference,
} = options;

if (!type && !typeToNamespacesMap) {
throw SavedObjectsErrorHelpers.createBadRequestError(
'options.type must be a string or an array of strings'
);
} else if (namespaces?.length === 0 && !typeToNamespacesMap) {
throw SavedObjectsErrorHelpers.createBadRequestError(
'options.namespaces cannot be an empty array'
);
} else if (type && typeToNamespacesMap) {
throw SavedObjectsErrorHelpers.createBadRequestError(
'options.type must be an empty string when options.typeToNamespacesMap is used'
);
} else if ((!namespaces || namespaces?.length) && typeToNamespacesMap) {
throw SavedObjectsErrorHelpers.createBadRequestError(
'options.namespaces must be an empty array when options.typeToNamespacesMap is used'
);
}

const types = Array.isArray(type) ? type : [type];
const types = type
? Array.isArray(type)
? type
: [type]
: Array.from(typeToNamespacesMap!.keys());
const allowedTypes = types.filter((t) => this._allowedTypes.includes(t));
if (allowedTypes.length === 0) {
return {
page,
per_page: perPage,
total: 0,
saved_objects: [],
};
return SavedObjectsUtils.createEmptyFindResponse<T>(options);
}

if (searchFields && !Array.isArray(searchFields)) {
Expand Down Expand Up @@ -766,6 +780,7 @@ export class SavedObjectsRepository {
sortField,
sortOrder,
namespaces,
typeToNamespacesMap,
hasReference,
kueryNode,
}),
Expand Down
Loading

0 comments on commit f8b449f

Please sign in to comment.