Skip to content

Commit 048ee0a

Browse files
Merge branch 'master' into issue-88744-sharing-saved-objects-guide
2 parents 469147b + 4f7e62f commit 048ee0a

File tree

327 files changed

+6076
-7356
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

327 files changed

+6076
-7356
lines changed

dev_docs/tutorials/saved_objects.mdx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ Since Elasticsearch has a default limit of 1000 fields per index, plugins should
126126
fields they add to the mappings. Similarly, Saved Object types should never use `dynamic: true` as this can cause an arbitrary
127127
amount of fields to be added to the .kibana index.
128128

129-
## References
129+
## References
130130

131131
Declare <DocLink id="kibDevDocsSavedObjectsIntro" section="References" text="Saved Object references"/> by adding an id, type and name to the
132132
`references` array.
@@ -159,12 +159,14 @@ identify this reference. This guarantees that the id the reference points to alw
159159
visualization id was directly stored in `dashboard.panels[0].visualization` there is a risk that this id gets updated without
160160
updating the reference in the references array.
161161

162-
## Writing migrations
162+
## Migrations
163163

164164
Saved Objects support schema changes between Kibana versions, which we call migrations. Migrations are
165-
applied when a Kibana installation is upgraded from one version to the next, when exports are imported via
165+
applied when a Kibana installation is upgraded from one version to a newer version, when exports are imported via
166166
the Saved Objects Management UI, or when a new object is created via the HTTP API.
167167

168+
### Writing migrations
169+
168170
Each Saved Object type may define migrations for its schema. Migrations are specified by the Kibana version number, receive an input document,
169171
and must return the fully migrated document to be persisted to Elasticsearch.
170172

@@ -245,10 +247,11 @@ export const dashboardVisualization: SavedObjectsType = {
245247
in which this migration was released. So if you are creating a migration which will
246248
be part of the v7.10.0 release, but will also be backported and released as v7.9.3, the migration version should be: 7.9.3.
247249

248-
Migrations should be written defensively, an exception in a migration function will prevent a Kibana upgrade from succeeding and will cause downtime for our users.
249-
Having said that, if a
250-
document is encountered that is not in the expected shape, migrations are encouraged to throw an exception to abort the upgrade. In most scenarios, it is better to
251-
fail an upgrade than to silently ignore a corrupt document which can cause unexpected behaviour at some future point in time.
250+
Migrations should be written defensively, an exception in a migration function will prevent a Kibana upgrade from succeeding and will cause downtime for our users.
251+
Having said that, if a document is encountered that is not in the expected shape, migrations are encouraged to throw an exception to abort the upgrade. In most scenarios, it is better to
252+
fail an upgrade than to silently ignore a corrupt document which can cause unexpected behaviour at some future point in time. When such a scenario is encountered,
253+
the error should be verbose and informative so that the corrupt document can be corrected, if possible.
254+
255+
### Testing Migrations
252256

253-
It is critical that you have extensive tests to ensure that migrations behave as expected with all possible input documents. Given how simple it is to test all the branch
254-
conditions in a migration function and the high impact of a bug in this code, there’s really no reason not to aim for 100% test code coverage.
257+
Bugs in a migration function cause downtime for our users and therefore have a very high impact. Follow the <DocLink id="kibDevTutorialTestingPlugins" section="saved-object-migrations" text="Saved Object migrations section in the plugin testing guide"/>.

dev_docs/tutorials/testing_plugins.mdx

Lines changed: 187 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ describe('renderApp', () => {
569569
});
570570
```
571571
572-
### SavedObjects
572+
### SavedObjectsClient
573573
574574
#### Unit Tests
575575
@@ -794,6 +794,192 @@ Kibana and esArchiver to load fixture data into Elasticsearch.
794794
795795
_todo: fully worked out example_
796796
797+
### Saved Objects migrations
798+
799+
_Also see <DocLink id="kibDevTutorialSavedObject" section="migrations" text="How to write a migration"/>._
800+
801+
It is critical that you have extensive tests to ensure that migrations behave as expected with all possible input
802+
documents. Given how simple it is to test all the branch conditions in a migration function and the high impact of a
803+
bug in this code, there’s really no reason not to aim for 100% test code coverage.
804+
805+
It's recommend that you primarily leverage unit testing with Jest for testing your migration function. Unit tests will
806+
be a much more effective approach to testing all the different shapes of input data and edge cases that your migration
807+
may need to handle. With more complex migrations that interact with several components or may behave different depending
808+
on registry contents (such as Embeddable migrations), we recommend that you use the Jest Integration suite which allows
809+
you to create a full instance Kibana and all plugins in memory and leverage the import API to test migrating documents.
810+
811+
#### Throwing exceptions
812+
Keep in mind that any exception thrown by your migration function will cause Kibana to fail to upgrade. This should almost
813+
never happen for our end users and we should be exhaustive in our testing to be sure to catch as many edge cases that we
814+
could possibly handle. This entails ensuring that the migration is written defensively; we should try to avoid every bug
815+
possible in our implementation.
816+
817+
In general, exceptions should only be thrown when the input data is corrupted and doesn't match the expected schema. In
818+
such cases, it's important that an informative error message is included in the exception and we do not rely on implicit
819+
runtime exceptions such as "null pointer exceptions" like `TypeError: Cannot read property 'foo' of undefined`.
820+
821+
#### Unit testing
822+
823+
Unit testing migration functions is typically pretty straight forward and comparable to other types of Jest testing. In
824+
general, you should focus this tier of testing on validating output and testing input edge cases. One focus of this tier
825+
should be trying to find edge cases that throw exceptions the migration shouldn't. As you can see in this simple
826+
example, the coverage here is very exhaustive and verbose, which is intentional.
827+
828+
```ts
829+
import { migrateCaseFromV7_9_0ToV7_10_0 } from './case_migrations';
830+
831+
const validInput_7_9_0 = {
832+
id: '1',
833+
type: 'case',
834+
attributes: {
835+
connector_id: '1234';
836+
}
837+
}
838+
839+
describe('Case migrations v7.7.0 -> v7.8.0', () => {
840+
it('transforms the connector field', () => {
841+
expect(migrateCaseFromV7_9_0ToV7_10_0(validInput_7_9_0)).toEqual({
842+
id: '1',
843+
type: 'case',
844+
attributes: {
845+
connector: {
846+
id: '1234', // verify id was moved into subobject
847+
name: 'none', // verify new default field was added
848+
}
849+
}
850+
});
851+
});
852+
853+
it('handles empty string', () => {
854+
expect(migrateCaseFromV7_9_0ToV7_10_0({
855+
id: '1',
856+
type: 'case',
857+
attributes: {
858+
connector_id: ''
859+
}
860+
})).toEqual({
861+
id: '1',
862+
type: 'case',
863+
attributes: {
864+
connector: {
865+
id: 'none',
866+
name: 'none',
867+
}
868+
}
869+
});
870+
});
871+
872+
it('handles null', () => {
873+
expect(migrateCaseFromV7_9_0ToV7_10_0({
874+
id: '1',
875+
type: 'case',
876+
attributes: {
877+
connector_id: null
878+
}
879+
})).toEqual({
880+
id: '1',
881+
type: 'case',
882+
attributes: {
883+
connector: {
884+
id: 'none',
885+
name: 'none',
886+
}
887+
}
888+
});
889+
});
890+
891+
it('handles undefined', () => {
892+
expect(migrateCaseFromV7_9_0ToV7_10_0({
893+
id: '1',
894+
type: 'case',
895+
attributes: {
896+
// Even though undefined isn't a valid JSON or Elasticsearch value, we should test it anyways since there
897+
// could be some JavaScript layer that casts the field to `undefined` for some reason.
898+
connector_id: undefined
899+
}
900+
})).toEqual({
901+
id: '1',
902+
type: 'case',
903+
attributes: {
904+
connector: {
905+
id: 'none',
906+
name: 'none',
907+
}
908+
}
909+
});
910+
911+
expect(migrateCaseFromV7_9_0ToV7_10_0({
912+
id: '1',
913+
type: 'case',
914+
attributes: {
915+
// also test without the field present at all
916+
}
917+
})).toEqual({
918+
id: '1',
919+
type: 'case',
920+
attributes: {
921+
connector: {
922+
id: 'none',
923+
name: 'none',
924+
}
925+
}
926+
});
927+
});
928+
});
929+
```
930+
931+
#### Integration testing
932+
With more complicated migrations, the behavior of the migration may be dependent on values from other plugins which may
933+
be difficult or even impossible to test with unit tests. You need to actually bootstrap Kibana, load the plugins, and
934+
then test the full end-to-end migration. This type of set up will also test ingesting your documents into Elasticsearch
935+
against the mappings defined by your Saved Object type.
936+
937+
This can be achieved using the `jest_integration` suite and the `kbnTestServer` utility for starting an in-memory
938+
instance of Kibana. You can then leverage the import API to test migrations. This API applies the same migrations to
939+
imported documents as are applied at Kibana startup and is much easier to work with for testing.
940+
941+
```ts
942+
// You may need to adjust these paths depending on where your test file is located.
943+
// The absolute path is src/core/test_helpers/so_migrations
944+
import { createTestHarness, SavedObjectTestHarness } from '../../../../src/core/test_helpers/so_migrations';
945+
946+
describe('my plugin migrations', () => {
947+
let testHarness: SavedObjectTestHarness;
948+
949+
beforeAll(async () => {
950+
testHarness = createTestHarness();
951+
await testHarness.start();
952+
});
953+
954+
afterAll(async () => {
955+
await testHarness.stop();
956+
});
957+
958+
it('successfully migrates valid case documents', async () => {
959+
expect(
960+
await testHarness.migrate([
961+
{ type: 'case', id: '1', attributes: { connector_id: '1234' }, references: [] },
962+
{ type: 'case', id: '2', attributes: { connector_id: '' }, references: [] },
963+
{ type: 'case', id: '3', attributes: { connector_id: null }, references: [] },
964+
])
965+
).toEqual([
966+
expect.objectContaining(
967+
{ type: 'case', id: '1', attributes: { connector: { id: '1234', name: 'none' } } }),
968+
expect.objectContaining(
969+
{ type: 'case', id: '2', attributes: { connector: { id: 'none', name: 'none' } } }),
970+
expect.objectContaining(
971+
{ type: 'case', id: '3', attributes: { connector: { id: 'none', name: 'none' } } }),
972+
])
973+
})
974+
})
975+
```
976+
977+
There are some caveats about using the import/export API for testing migrations:
978+
- You cannot test the startup behavior of Kibana this way. This should not have any effect on type migrations but does
979+
mean that this method cannot be used for testing the migration algorithm itself.
980+
- While not yet supported, if support is added for migrations that affect multiple types, it's possible that the
981+
behavior during import may vary slightly from the upgrade behavior.
982+
797983
### Elasticsearch
798984
799985
_How to test ES clients_

docs/CHANGELOG.asciidoc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ This section summarizes the changes in each release.
1818
[[release-notes-8.0.0-alpha1]]
1919
== {kib} 8.0.0-alpha1
2020

21-
coming[8.0.0]
22-
2321
The following changes are released for the first time in {kib} 8.0.0-alpha1. Review the changes, then use the <<upgrade-assistant,Upgrade Assistant>> to complete the upgrade.
2422

2523
[float]

docs/maps/import-geospatial-data.asciidoc

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ To import geospatical data into the Elastic Stack, the data must be indexed as {
66
Geospatial data comes in many formats.
77
Choose an import tool based on the format of your geospatial data.
88

9+
TIP: When you upload GeoJSON or delimited files in {kib}, there is a file size
10+
limit, which is configurable in <<fileupload-maxfilesize,Advanced Settings>>.
11+
912
[discrete]
1013
[[import-geospatial-privileges]]
1114
=== Security privileges
@@ -18,37 +21,36 @@ spaces in **{stack-manage-app}** in {kib}. For more information, see
1821

1922
To upload GeoJSON files in {kib} with *Maps*, you must have:
2023

21-
* The `all` {kib} privilege for *Maps*.
22-
* The `all` {kib} privilege for *Index Pattern Management*.
23-
* The `create` and `create_index` index privileges for destination indices.
24-
* To use the index in *Maps*, you must also have the `read` and `view_index_metadata` index privileges for destination indices.
24+
* The `all` {kib} privilege for *Maps*
25+
* The `all` {kib} privilege for *{ipm-app}*
26+
* The `create` and `create_index` index privileges for destination indices
27+
* To use the index in *Maps*, you must also have the `read` and `view_index_metadata` index privileges for destination indices
2528

26-
To upload CSV files in {kib} with the *{file-data-viz}*, you must have privileges to upload GeoJSON files and:
29+
To upload delimited files (such as CSV, TSV, or JSON files) on the {kib} home page, you must also have:
2730

28-
* The `manage_pipeline` cluster privilege.
29-
* The `read` {kib} privilege for *Machine Learning*.
30-
* The `machine_learning_admin` or `machine_learning_user` role.
31+
* The `all` {kib} privilege for *Discover*
32+
* The `manage_pipeline` or `manage_ingest_pipelines` cluster privilege
33+
* The `manage` index privilege for destination indices
3134

3235

3336
[discrete]
34-
=== Upload CSV with latitude and longitude columns
37+
=== Upload delimited files with latitude and longitude columns
3538

36-
*File Data Visualizer* indexes CSV files with latitude and longitude columns as a geo_point.
39+
On the {kib} home page, you can upload a file and import it into an {es} index with latitude and longitude columns combined into a `geo_point` field.
3740

38-
. Open the main menu, then click *Machine Learning*.
39-
. Select the *Data Visualizer* tab, then click *Upload file*.
40-
. Use the file chooser to select a CSV file.
41+
. Go to the {kib} home page and click *Upload a file*.
42+
. Select a file in one of the supported file formats.
4143
. Click *Import*.
4244
. Select the *Advanced* tab.
4345
. Set *Index name*.
44-
. Click *Add combined field*, then click *Add geo point field*.
46+
. If a combined `geo_point` field is not created automatically, click *Add combined field*, then click *Add geo point field*.
4547
. Fill out the form and click *Add*.
4648
. Click *Import*.
4749

4850
[discrete]
4951
=== Upload a GeoJSON file
5052

51-
*Upload GeoJSON* indexes GeoJSON features as a geo_point or geo_shape.
53+
*Upload GeoJSON* indexes GeoJSON features as a `geo_point` or `geo_shape`.
5254

5355
. <<maps-create, Create a new map>>.
5456
. Click *Add layer*.

packages/kbn-test/src/jest/utils/get_url.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ interface UrlParam {
2222
username?: string;
2323
}
2424

25+
interface App {
26+
pathname?: string;
27+
hash?: string;
28+
}
29+
2530
/**
2631
* Converts a config and a pathname to a url
2732
* @param {object} config A url config
@@ -41,11 +46,11 @@ interface UrlParam {
4146
* @return {string}
4247
*/
4348

44-
function getUrl(config: UrlParam, app: UrlParam) {
49+
function getUrl(config: UrlParam, app: App) {
4550
return url.format(_.assign({}, config, app));
4651
}
4752

48-
getUrl.noAuth = function getUrlNoAuth(config: UrlParam, app: UrlParam) {
53+
getUrl.noAuth = function getUrlNoAuth(config: UrlParam, app: App) {
4954
config = _.pickBy(config, function (val, param) {
5055
return param !== 'auth';
5156
});

src/core/server/saved_objects/migrations/core/elastic_index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ export const REMOVED_TYPES: string[] = [
4343
'server',
4444
// https://github.com/elastic/kibana/issues/95617
4545
'tsvb-validation-telemetry',
46+
// replaced by osquery-manager-usage-metric
47+
'osquery-usage-metric',
4648
].sort();
4749

4850
// When migrating from the outdated index we use a read query which excludes

src/core/server/saved_objects/migrationsv2/integration_tests/type_registrations.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ const previouslyRegisteredTypes = [
7272
'monitoring-telemetry',
7373
'osquery-saved-query',
7474
'osquery-usage-metric',
75+
'osquery-manager-usage-metric',
7576
'query',
7677
'sample-data-telemetry',
7778
'search',

src/plugins/discover/public/__mocks__/services.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ import { DiscoverServices } from '../build_services';
1010
import { dataPluginMock } from '../../../data/public/mocks';
1111
import { chromeServiceMock, coreMock, docLinksServiceMock } from '../../../../core/public/mocks';
1212
import {
13+
CONTEXT_STEP_SETTING,
1314
DEFAULT_COLUMNS_SETTING,
15+
DOC_HIDE_TIME_COLUMN_SETTING,
1416
SAMPLE_SIZE_SETTING,
1517
SORT_DEFAULT_ORDER_SETTING,
1618
} from '../../common';
1719
import { savedSearchMock } from './saved_search';
1820
import { UI_SETTINGS } from '../../../data/common';
1921
import { TopNavMenu } from '../../../navigation/public';
22+
import { FORMATS_UI_SETTINGS } from 'src/plugins/field_formats/common';
2023
const dataPlugin = dataPluginMock.createStartContract();
2124

2225
export const discoverServiceMock = ({
@@ -49,10 +52,16 @@ export const discoverServiceMock = ({
4952
return [];
5053
} else if (key === UI_SETTINGS.META_FIELDS) {
5154
return [];
52-
} else if (key === SAMPLE_SIZE_SETTING) {
53-
return 250;
55+
} else if (key === DOC_HIDE_TIME_COLUMN_SETTING) {
56+
return false;
57+
} else if (key === CONTEXT_STEP_SETTING) {
58+
return 5;
5459
} else if (key === SORT_DEFAULT_ORDER_SETTING) {
5560
return 'desc';
61+
} else if (key === FORMATS_UI_SETTINGS.SHORT_DOTS_ENABLE) {
62+
return false;
63+
} else if (key === SAMPLE_SIZE_SETTING) {
64+
return 250;
5665
}
5766
},
5867
isDefault: (key: string) => {

0 commit comments

Comments
 (0)