diff --git a/dev_docs/tutorials/advanced_settings.mdx b/dev_docs/tutorials/advanced_settings.mdx index 4e5e208fc68f0c..1ca925e24f54a0 100644 --- a/dev_docs/tutorials/advanced_settings.mdx +++ b/dev_docs/tutorials/advanced_settings.mdx @@ -286,3 +286,13 @@ export const migrations = { }; ``` [1] Since all `uiSettings` migrations are added to the same migration function, while not required, grouping settings by team is good practice. + +### Creating Transforms + +If you have need to make a change that isn't possible in a saved object migration function (for example, you need to find other saved +objects), you can create a transform function instead. This will be applied when a `config` saved object is first created, and/or when it is +first upgraded. Note that you might need to add an extra attribute to verify that this transform has already been applied so it doesn't get +applied again in the future. + +For example, we needed to transform the `defaultIndex` attribute, and we added an extra `isDefaultIndexMigrated` attribute for this purpose. +See `src/core/server/ui_settings/saved_objects/transforms.ts` and [#13339](https://github.com/elastic/kibana/pull/133339) for an example. diff --git a/docs/api/actions-and-connectors.asciidoc b/docs/api/actions-and-connectors.asciidoc index f8d286e00b856f..b35fa57668859f 100644 --- a/docs/api/actions-and-connectors.asciidoc +++ b/docs/api/actions-and-connectors.asciidoc @@ -28,7 +28,7 @@ include::actions-and-connectors/delete.asciidoc[leveloffset=+1] include::actions-and-connectors/get.asciidoc[leveloffset=+1] include::actions-and-connectors/get_all.asciidoc[leveloffset=+1] include::actions-and-connectors/list.asciidoc[] -include::actions-and-connectors/update.asciidoc[] +include::actions-and-connectors/update.asciidoc[leveloffset=+1] include::actions-and-connectors/execute.asciidoc[] include::actions-and-connectors/legacy/index.asciidoc[] include::actions-and-connectors/legacy/get.asciidoc[] diff --git a/docs/api/actions-and-connectors/create.asciidoc b/docs/api/actions-and-connectors/create.asciidoc index a118ef1e20a1bf..b8334573d2330b 100644 --- a/docs/api/actions-and-connectors/create.asciidoc +++ b/docs/api/actions-and-connectors/create.asciidoc @@ -34,6 +34,8 @@ You must have `all` privileges for the *Actions and Connectors* feature in the (Required, object) The configuration for the connector. Configuration properties vary depending on the connector type. For example: + +-- +// tag::connector-config[] .Index connectors [%collapsible%open] ==== @@ -51,7 +53,7 @@ request. The default value is `false`. For more information, refer to {kibana-ref}/index-action-type.html[Index connector and action]. ==== -+ + .{jira} connectors [%collapsible%open] ==== @@ -65,8 +67,10 @@ For more information, refer to For more information, refer to {kibana-ref}/jira-action-type.html[{jira} connector and action]. ==== -+ + For more configuration properties, refer to <>. +// end::connector-config[] +-- `connector_type_id`:: (Required, string) The connector type ID for the connector. @@ -75,7 +79,7 @@ For more configuration properties, refer to <>. (Required, string) The display name for the connector. `secrets`:: -(Required, object) The secrets configuration for the connector. Secrets +(Required^*^, object) The secrets configuration for the connector. Secrets configuration properties vary depending on the connector type. For information about the secrets configuration properties, refer to <>. + @@ -83,6 +87,8 @@ about the secrets configuration properties, refer to <>. WARNING: Remember these values. You must provide them each time you call the <> API. -- + +-- +// tag::connector-secrets[] .{jira} connectors [%collapsible%open] ==== @@ -93,6 +99,8 @@ authentication. `email`:: (Required, string) The account email for HTTP Basic authentication. ==== +// end::connector-secrets[] +-- [[create-connector-api-request-codes]] === {api-response-codes-title} diff --git a/docs/api/actions-and-connectors/execute.asciidoc b/docs/api/actions-and-connectors/execute.asciidoc index e830c9b4bbf886..2ddd311836281a 100644 --- a/docs/api/actions-and-connectors/execute.asciidoc +++ b/docs/api/actions-and-connectors/execute.asciidoc @@ -7,14 +7,24 @@ Executes a connector by ID. [[execute-connector-api-request]] -==== Request +==== {api-request-title} `POST :/api/actions/connector//_execute` `POST :/s//api/actions/connector//_execute` +[discrete] +=== {api-prereq-title} + +You must have `read` privileges for the *Actions and Connectors* feature in the +*Management* section of the +<>. + +If you use an index connector, you must also have `all`, `create`, `index`, or +`write` {ref}/security-privileges.html[indices privileges]. + [[execute-connector-api-params]] -==== Path parameters +==== {api-path-parms-title} `id`:: (Required, string) The ID of the connector. @@ -23,24 +33,26 @@ Executes a connector by ID. (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. [[execute-connector-api-request-body]] -==== Request body +==== {api-request-body-title} `params`:: (Required, object) The parameters of the connector. Parameter properties vary depending on the connector type. For information about the parameter properties, refer to <>. [[execute-connector-api-codes]] -==== Response code +==== {api-response-codes-title} `200`:: Indicates a successful call. [[execute-connector-api-example]] -==== Example +==== {api-examples-title} + +Run an index connector: [source,sh] -------------------------------------------------- -$ curl -X POST api/actions/connector/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad/_execute -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d ' +POST api/actions/connector/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad/_execute { "params": { "documents": [ @@ -51,7 +63,7 @@ $ curl -X POST api/actions/connector/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad/_execu } ] } -}' +} -------------------------------------------------- // KIBANA @@ -62,7 +74,7 @@ The API returns the following: { "status": "ok", "data": { - "took": 197, + "took": 10, "errors": false, "items": [ { @@ -76,7 +88,7 @@ The API returns the following: "successful": 1, "failed": 0 }, - "_seq_no": 0, + "_seq_no": 7, "_primary_term": 1, "status": 201 } diff --git a/docs/api/actions-and-connectors/list.asciidoc b/docs/api/actions-and-connectors/list.asciidoc index bd1ccb777b9aef..a2542c6ca3aaf6 100644 --- a/docs/api/actions-and-connectors/list.asciidoc +++ b/docs/api/actions-and-connectors/list.asciidoc @@ -7,30 +7,37 @@ Retrieves a list of all connector types. [[list-connector-types-api-request]] -==== Request +==== {api-request-title} `GET :/api/actions/connector_types` `GET :/s//api/actions/connector_types` + +[discrete] +=== {api-prereq-title} + +You do not need any <> to +run this API. + [[list-connector-types-api-path-params]] -==== Path parameters +==== {api-path-parms-title} `space_id`:: (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. [[list-connector-types-api-codes]] -==== Response code +==== {api-response-codes-title} `200`:: Indicates a successful call. [[list-connector-types-api-example]] -==== Example +==== {api-examples-title} [source,sh] -------------------------------------------------- -$ curl -X GET api/actions/connector_types +GET api/actions/connector_types -------------------------------------------------- // KIBANA @@ -45,7 +52,7 @@ The API returns the following: "minimum_license_required": "gold", <3> "enabled": false, <4> "enabled_in_config": true, <5> - "enabled_in_license": false <6> + "enabled_in_license": true <6> }, { "id": ".index", @@ -54,14 +61,13 @@ The API returns the following: "enabled": true, "enabled_in_config": true, "enabled_in_license": true - } + }, + ... ] -------------------------------------------------- - - <1> `id` - The unique ID of the connector type. <2> `name` - The name of the connector type. <3> `minimum_license_required` - The license required to use the connector type. <4> `enabled` - Specifies if the connector type is enabled or disabled in {kib}. -<5> `enabled_in_config` - Specifies if the connector type is enabled or enabled in the {kib} .yml file. +<5> `enabled_in_config` - Specifies if the connector type is enabled or enabled in the {kib} `.yml` file. <6> `enabled_in_license` - Specifies if the connector type is enabled or disabled in the license. diff --git a/docs/api/actions-and-connectors/update.asciidoc b/docs/api/actions-and-connectors/update.asciidoc index 7ccb10714f4742..58056cb8085f94 100644 --- a/docs/api/actions-and-connectors/update.asciidoc +++ b/docs/api/actions-and-connectors/update.asciidoc @@ -1,20 +1,27 @@ [[update-connector-api]] -=== Update connector API +== Update connector API ++++ Update connector ++++ -Updates the attributes for an existing connector. +Updates the attributes for a connector. [[update-connector-api-request]] -==== Request +=== {api-request-title} `PUT :/api/actions/connector/` `PUT :/s//api/actions/connector/` +[discrete] +=== {api-prereq-title} + +You must have `all` privileges for the *Actions and Connectors* feature in the +*Management* section of the +<>. + [[update-connector-api-params]] -==== Path parameters +=== {api-path-parms-title} `id`:: (Required, string) The ID of the connector. @@ -22,36 +29,49 @@ Updates the attributes for an existing connector. `space_id`:: (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. +[role="child_attributes"] [[update-connector-api-request-body]] -==== Request body - -`name`:: - (Required, string) The new name of the connector. +=== {api-request-body-title} `config`:: - (Required, object) The new connector configuration. Configuration properties vary depending on the connector type. For information about the configuration properties, refer to <>. +(Required, object) The new connector configuration. Configuration properties +vary depending on the connector type. For example: ++ +-- +include::create.asciidoc[tag=connector-config] +-- + +`name`:: +(Required, string) The new name of the connector. `secrets`:: - (Required, object) The updated secrets configuration for the connector. Secrets properties vary depending on the connector type. For information about the secrets configuration properties, refer to <>. +(Required^*^, object) The updated secrets configuration for the connector. Secrets +properties vary depending on the connector type. For information about the +secrets configuration properties, refer to +<>. ++ +-- +include::create.asciidoc[tag=connector-secrets] +-- [[update-connector-api-codes]] -==== Response code +=== {api-response-codes-title} `200`:: Indicates a successful call. [[update-connector-api-example]] -==== Example +=== {api-examples-title} [source,sh] -------------------------------------------------- -$ curl -X PUT api/actions/connector/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d ' +PUT api/actions/connector/c55b6eb0-6bad-11eb-9f3b-611eebc6c3ad { "name": "updated-connector", "config": { "index": "updated-index" } -}' +} -------------------------------------------------- // KIBANA diff --git a/docs/management/cases/images/cases-visualization.png b/docs/management/cases/images/cases-visualization.png index 77f249f26d0912..53c4893bcc598a 100644 Binary files a/docs/management/cases/images/cases-visualization.png and b/docs/management/cases/images/cases-visualization.png differ diff --git a/docs/management/cases/images/cases.png b/docs/management/cases/images/cases.png index b244b3df16a209..a69f21c2ec9f8e 100644 Binary files a/docs/management/cases/images/cases.png and b/docs/management/cases/images/cases.png differ diff --git a/packages/kbn-field-types/src/kbn_field_types_factory.ts b/packages/kbn-field-types/src/kbn_field_types_factory.ts index 2ded968c3cdf49..02f7c7444862d1 100644 --- a/packages/kbn-field-types/src/kbn_field_types_factory.ts +++ b/packages/kbn-field-types/src/kbn_field_types_factory.ts @@ -21,6 +21,7 @@ export const createKbnFieldTypes = (): KbnFieldType[] => [ esTypes: [ ES_FIELD_TYPES.STRING, ES_FIELD_TYPES.TEXT, + ES_FIELD_TYPES.MATCH_ONLY_TEXT, ES_FIELD_TYPES.KEYWORD, ES_FIELD_TYPES.VERSION, ES_FIELD_TYPES._TYPE, diff --git a/packages/kbn-field-types/src/types.ts b/packages/kbn-field-types/src/types.ts index c14e7e4b03661a..0addc2c5bf077a 100644 --- a/packages/kbn-field-types/src/types.ts +++ b/packages/kbn-field-types/src/types.ts @@ -23,6 +23,7 @@ export enum ES_FIELD_TYPES { STRING = 'string', TEXT = 'text', + MATCH_ONLY_TEXT = 'match_only_text', KEYWORD = 'keyword', VERSION = 'version', diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.mock.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.mock.ts index 11dabaca71e13b..11ff892b89bf12 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.mock.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.mock.ts @@ -6,7 +6,17 @@ * Side Public License, v 1. */ -export const createOrUpgradeSavedConfigMock = jest.fn(); -jest.doMock('./create_or_upgrade_saved_config', () => ({ - createOrUpgradeSavedConfig: createOrUpgradeSavedConfigMock, +import type { TransformConfigFn } from '../saved_objects'; +import type { getUpgradeableConfig } from './get_upgradeable_config'; + +export const mockTransform = jest.fn() as jest.MockedFunction; +jest.mock('../saved_objects', () => ({ + transforms: [mockTransform], +})); + +export const mockGetUpgradeableConfig = jest.fn() as jest.MockedFunction< + typeof getUpgradeableConfig +>; +jest.mock('./get_upgradeable_config', () => ({ + getUpgradeableConfig: mockGetUpgradeableConfig, })); diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.ts index 669849dcd8d9be..fe6aa83bb02961 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.ts @@ -6,29 +6,28 @@ * Side Public License, v 1. */ -import Chance from 'chance'; - -import { getUpgradeableConfigMock } from './get_upgradeable_config.test.mock'; +import { + mockTransform, + mockGetUpgradeableConfig, +} from './create_or_upgrade_saved_config.test.mock'; import { SavedObjectsErrorHelpers } from '../../saved_objects'; import { savedObjectsClientMock } from '../../saved_objects/service/saved_objects_client.mock'; import { loggingSystemMock } from '../../logging/logging_system.mock'; import { createOrUpgradeSavedConfig } from './create_or_upgrade_saved_config'; -const chance = new Chance(); describe('uiSettings/createOrUpgradeSavedConfig', function () { afterEach(() => jest.resetAllMocks()); const version = '4.0.1'; const prevVersion = '4.0.0'; - const buildNum = chance.integer({ min: 1000, max: 5000 }); + const buildNum = 1337; function setup() { const logger = loggingSystemMock.create(); - const getUpgradeableConfig = getUpgradeableConfigMock; const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.create.mockImplementation( - async (type, attributes, options = {}) => + async (type, _, options = {}) => ({ type, id: options.id, @@ -46,8 +45,8 @@ describe('uiSettings/createOrUpgradeSavedConfig', function () { ...options, }); - expect(getUpgradeableConfigMock).toHaveBeenCalledTimes(1); - expect(getUpgradeableConfig).toHaveBeenCalledWith({ savedObjectsClient, version }); + expect(mockGetUpgradeableConfig).toHaveBeenCalledTimes(1); + expect(mockGetUpgradeableConfig).toHaveBeenCalledWith({ savedObjectsClient, version }); return resp; } @@ -58,7 +57,6 @@ describe('uiSettings/createOrUpgradeSavedConfig', function () { run, version, savedObjectsClient, - getUpgradeableConfig, }; } @@ -83,25 +81,21 @@ describe('uiSettings/createOrUpgradeSavedConfig', function () { describe('something is upgradeable', () => { it('should merge upgraded attributes with current build number in new config', async () => { - const { run, getUpgradeableConfig, savedObjectsClient } = setup(); + const { run, savedObjectsClient } = setup(); const savedAttributes = { buildNum: buildNum - 100, - [chance.word()]: chance.sentence(), - [chance.word()]: chance.sentence(), - [chance.word()]: chance.sentence(), + defaultIndex: 'some-index', }; - getUpgradeableConfig.mockResolvedValue({ + mockGetUpgradeableConfig.mockResolvedValue({ id: prevVersion, attributes: savedAttributes, - type: '', - references: [], }); await run(); - expect(getUpgradeableConfig).toHaveBeenCalledTimes(1); + expect(mockGetUpgradeableConfig).toHaveBeenCalledTimes(1); expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); expect(savedObjectsClient.create).toHaveBeenCalledWith( 'config', @@ -115,14 +109,42 @@ describe('uiSettings/createOrUpgradeSavedConfig', function () { ); }); + it('should prefer transformed attributes when merging', async () => { + const { run, savedObjectsClient } = setup(); + mockGetUpgradeableConfig.mockResolvedValue({ + id: prevVersion, + attributes: { + buildNum: buildNum - 100, + defaultIndex: 'some-index', + }, + }); + mockTransform.mockResolvedValue({ + defaultIndex: 'another-index', + isDefaultIndexMigrated: true, + }); + + await run(); + + expect(mockGetUpgradeableConfig).toHaveBeenCalledTimes(1); + expect(mockTransform).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.create).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.create).toHaveBeenCalledWith( + 'config', + { + buildNum, + defaultIndex: 'another-index', + isDefaultIndexMigrated: true, + }, + { id: version } + ); + }); + it('should log a message for upgrades', async () => { - const { getUpgradeableConfig, logger, run } = setup(); + const { logger, run } = setup(); - getUpgradeableConfig.mockResolvedValue({ + mockGetUpgradeableConfig.mockResolvedValue({ id: prevVersion, attributes: { buildNum: buildNum - 100 }, - type: '', - references: [], }); await run(); @@ -144,13 +166,11 @@ describe('uiSettings/createOrUpgradeSavedConfig', function () { }); it('does not log when upgrade fails', async () => { - const { getUpgradeableConfig, logger, run, savedObjectsClient } = setup(); + const { logger, run, savedObjectsClient } = setup(); - getUpgradeableConfig.mockResolvedValue({ + mockGetUpgradeableConfig.mockResolvedValue({ id: prevVersion, attributes: { buildNum: buildNum - 100 }, - type: '', - references: [], }); savedObjectsClient.create.mockRejectedValue(new Error('foo')); diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts index d55a6537957cbd..247a3cce974f47 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/create_or_upgrade_saved_config.ts @@ -9,10 +9,12 @@ import { defaults } from 'lodash'; import type { Logger, LogMeta } from '@kbn/logging'; +import { asyncForEach } from '@kbn/std'; import { SavedObjectsClientContract } from '../../saved_objects/types'; import { SavedObjectsErrorHelpers } from '../../saved_objects'; import { getUpgradeableConfig } from './get_upgradeable_config'; +import { transforms } from '../saved_objects'; interface ConfigLogMeta extends LogMeta { kibana: { @@ -39,10 +41,22 @@ export async function createOrUpgradeSavedConfig( version, }); + let transformDefaults = {}; + await asyncForEach(transforms, async (transformFn) => { + const result = await transformFn({ + savedObjectsClient, + configAttributes: upgradeableConfig?.attributes, + }); + transformDefaults = { ...transformDefaults, ...result }; + }); + // default to the attributes of the upgradeableConfig if available const attributes = defaults( - { buildNum }, - upgradeableConfig ? (upgradeableConfig.attributes as any) : {} + { + buildNum, + ...transformDefaults, // Any defaults that should be applied from transforms + }, + upgradeableConfig?.attributes ); try { diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.test.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.test.ts index 320fa9056fcaf9..34ef0c5b4f2e14 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.test.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.test.ts @@ -8,69 +8,70 @@ import { getUpgradeableConfig } from './get_upgradeable_config'; import { savedObjectsClientMock } from '../../saved_objects/service/saved_objects_client.mock'; +import { SavedObjectsFindResponse } from '../../saved_objects'; describe('getUpgradeableConfig', () => { it('finds saved objects with type "config"', async () => { const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.find.mockResolvedValue({ - saved_objects: [{ id: '7.5.0' }], - } as any); + saved_objects: [{ id: '7.5.0', attributes: 'foo' }], + } as SavedObjectsFindResponse); await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' }); expect(savedObjectsClient.find.mock.calls[0][0].type).toBe('config'); }); it('finds saved config with version < than Kibana version', async () => { - const savedConfig = { id: '7.4.0' }; + const savedConfig = { id: '7.4.0', attributes: 'foo' }; const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.find.mockResolvedValue({ saved_objects: [savedConfig], - } as any); + } as SavedObjectsFindResponse); const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' }); - expect(result).toBe(savedConfig); + expect(result).toEqual(savedConfig); }); it('finds saved config with RC version === Kibana version', async () => { - const savedConfig = { id: '7.5.0-rc1' }; + const savedConfig = { id: '7.5.0-rc1', attributes: 'foo' }; const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.find.mockResolvedValue({ saved_objects: [savedConfig], - } as any); + } as SavedObjectsFindResponse); const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' }); - expect(result).toBe(savedConfig); + expect(result).toEqual(savedConfig); }); it('does not find saved config with version === Kibana version', async () => { - const savedConfig = { id: '7.5.0' }; + const savedConfig = { id: '7.5.0', attributes: 'foo' }; const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.find.mockResolvedValue({ saved_objects: [savedConfig], - } as any); + } as SavedObjectsFindResponse); const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' }); - expect(result).toBe(undefined); + expect(result).toBe(null); }); it('does not find saved config with version > Kibana version', async () => { - const savedConfig = { id: '7.6.0' }; + const savedConfig = { id: '7.6.0', attributes: 'foo' }; const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.find.mockResolvedValue({ saved_objects: [savedConfig], - } as any); + } as SavedObjectsFindResponse); const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' }); - expect(result).toBe(undefined); + expect(result).toBe(null); }); it('handles empty config', async () => { const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.find.mockResolvedValue({ saved_objects: [], - } as any); + } as unknown as SavedObjectsFindResponse); const result = await getUpgradeableConfig({ savedObjectsClient, version: '7.5.0' }); - expect(result).toBe(undefined); + expect(result).toBe(null); }); }); diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.ts index 493efa518f22ba..6c8e8cbe9ac3af 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.ts @@ -7,8 +7,18 @@ */ import { SavedObjectsClientContract } from '../../saved_objects/types'; +import type { ConfigAttributes } from '../saved_objects'; import { isConfigVersionUpgradeable } from './is_config_version_upgradeable'; +/** + * This contains a subset of `config` object attributes that are relevant for upgrading it using transform functions. + * It is a superset of all the attributes needed for all of the transform functions defined in `transforms.ts`. + */ +export interface UpgradeableConfigAttributes extends ConfigAttributes { + defaultIndex?: string; + isDefaultIndexMigrated?: boolean; +} + /** * Find the most recent SavedConfig that is upgradeable to the specified version * @param {Object} options @@ -24,14 +34,21 @@ export async function getUpgradeableConfig({ version: string; }) { // attempt to find a config we can upgrade - const { saved_objects: savedConfigs } = await savedObjectsClient.find({ - type: 'config', - page: 1, - perPage: 1000, - sortField: 'buildNum', - sortOrder: 'desc', - }); + const { saved_objects: savedConfigs } = + await savedObjectsClient.find({ + type: 'config', + page: 1, + perPage: 1000, + sortField: 'buildNum', + sortOrder: 'desc', + }); // try to find a config that we can upgrade - return savedConfigs.find((savedConfig) => isConfigVersionUpgradeable(savedConfig.id, version)); + const findResult = savedConfigs.find((savedConfig) => + isConfigVersionUpgradeable(savedConfig.id, version) + ); + if (findResult) { + return { id: findResult.id, attributes: findResult.attributes }; + } + return null; } diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/index.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/index.ts index 3559c8555803ae..e5f8f895e86317 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/index.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/index.ts @@ -7,3 +7,4 @@ */ export { createOrUpgradeSavedConfig } from './create_or_upgrade_saved_config'; +export type { UpgradeableConfigAttributes } from './get_upgradeable_config'; diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts index 1da8bad330c31b..44efc558e10292 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts @@ -90,6 +90,9 @@ describe('createOrUpgradeSavedConfig()', () => { // 5.4.0-SNAPSHOT and @@version were ignored so we only have the // attributes from 5.4.0-rc1, even though the other build nums are greater '5.4.0-rc1': true, + + // Should have the transform(s) applied + isDefaultIndexMigrated: true, }); // add the 5.4.0 flag to the 5.4.0 savedConfig @@ -115,6 +118,9 @@ describe('createOrUpgradeSavedConfig()', () => { // should also include properties from 5.4.0 and 5.4.0-rc1 '5.4.0': true, '5.4.0-rc1': true, + + // Should have the transform(s) applied + isDefaultIndexMigrated: true, }); // add the 5.4.1 flag to the 5.4.1 savedConfig @@ -141,6 +147,9 @@ describe('createOrUpgradeSavedConfig()', () => { '5.4.1': true, '5.4.0': true, '5.4.0-rc1': true, + + // Should have the transform(s) applied + isDefaultIndexMigrated: true, }); // tag the 7.0.0-rc1 doc @@ -168,6 +177,9 @@ describe('createOrUpgradeSavedConfig()', () => { '5.4.1': true, '5.4.0': true, '5.4.0-rc1': true, + + // Should have the transform(s) applied + isDefaultIndexMigrated: true, }); // tag the 7.0.0 doc @@ -194,6 +206,9 @@ describe('createOrUpgradeSavedConfig()', () => { '5.4.1': true, '5.4.0': true, '5.4.0-rc1': true, + + // Should have the transform(s) applied + isDefaultIndexMigrated: true, }); }, 30000); }); diff --git a/src/core/server/ui_settings/saved_objects/index.ts b/src/core/server/ui_settings/saved_objects/index.ts index eb8e7cfcc2a1b2..92ef9961bb9084 100644 --- a/src/core/server/ui_settings/saved_objects/index.ts +++ b/src/core/server/ui_settings/saved_objects/index.ts @@ -6,4 +6,7 @@ * Side Public License, v 1. */ +export type { ConfigAttributes } from './ui_settings'; export { uiSettingsType } from './ui_settings'; +export type { TransformConfigFn } from './transforms'; +export { transforms } from './transforms'; diff --git a/src/core/server/ui_settings/saved_objects/transforms.test.ts b/src/core/server/ui_settings/saved_objects/transforms.test.ts new file mode 100644 index 00000000000000..afcd525673aa09 --- /dev/null +++ b/src/core/server/ui_settings/saved_objects/transforms.test.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { savedObjectsClientMock } from '../../mocks'; +import { SavedObjectsErrorHelpers } from '../../saved_objects'; +import { SavedObject } from '../../types'; +import type { UpgradeableConfigAttributes } from '../create_or_upgrade_saved_config'; +import { transformDefaultIndex } from './transforms'; + +/** + * Test each transform function individually, not the entire exported `transforms` array. + */ +describe('#transformDefaultIndex', () => { + const savedObjectsClient = savedObjectsClientMock.create(); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should return early if the config object has already been transformed', async () => { + const result = await transformDefaultIndex({ + savedObjectsClient, + configAttributes: { isDefaultIndexMigrated: true } as UpgradeableConfigAttributes, // We don't care about the other attributes + }); + + expect(savedObjectsClient.resolve).not.toHaveBeenCalled(); + expect(result).toEqual(null); // This is the only time we expect a null result + }); + + it('should return early if configAttributes is undefined', async () => { + const result = await transformDefaultIndex({ savedObjectsClient, configAttributes: undefined }); + + expect(savedObjectsClient.resolve).not.toHaveBeenCalled(); + expect(result).toEqual({ isDefaultIndexMigrated: true }); + }); + + it('should return early if the defaultIndex attribute is undefined', async () => { + const result = await transformDefaultIndex({ + savedObjectsClient, + configAttributes: { defaultIndex: undefined } as UpgradeableConfigAttributes, // We don't care about the other attributes + }); + + expect(savedObjectsClient.resolve).not.toHaveBeenCalled(); + expect(result).toEqual({ isDefaultIndexMigrated: true }); + }); + + describe('should resolve the data view for the defaultIndex and return the result according to the outcome', () => { + it('outcome: exactMatch', async () => { + savedObjectsClient.resolve.mockResolvedValue({ + outcome: 'exactMatch', + alias_target_id: 'another-index', // This wouldn't realistically be set if the outcome is exactMatch, but we're including it in this test to assert that the returned defaultIndex will be 'some-index' + saved_object: {} as SavedObject, // Doesn't matter + }); + const result = await transformDefaultIndex({ + savedObjectsClient, + configAttributes: { defaultIndex: 'some-index' } as UpgradeableConfigAttributes, // We don't care about the other attributes + }); + + expect(savedObjectsClient.resolve).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.resolve).toHaveBeenCalledWith('index-pattern', 'some-index'); + expect(result).toEqual({ isDefaultIndexMigrated: true, defaultIndex: 'some-index' }); + }); + + for (const outcome of ['aliasMatch' as const, 'conflict' as const]) { + it(`outcome: ${outcome}`, async () => { + savedObjectsClient.resolve.mockResolvedValue({ + outcome, + alias_target_id: 'another-index', + saved_object: {} as SavedObject, // Doesn't matter + }); + const result = await transformDefaultIndex({ + savedObjectsClient, + configAttributes: { defaultIndex: 'some-index' } as UpgradeableConfigAttributes, // We don't care about the other attributes + }); + + expect(savedObjectsClient.resolve).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.resolve).toHaveBeenCalledWith('index-pattern', 'some-index'); + expect(result).toEqual({ isDefaultIndexMigrated: true, defaultIndex: 'another-index' }); + }); + } + + it('returns the expected result if resolve fails with a Not Found error', async () => { + savedObjectsClient.resolve.mockRejectedValue( + SavedObjectsErrorHelpers.createGenericNotFoundError('Oh no!') + ); + const result = await transformDefaultIndex({ + savedObjectsClient, + configAttributes: { defaultIndex: 'some-index' } as UpgradeableConfigAttributes, // We don't care about the other attributes + }); + + expect(savedObjectsClient.resolve).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.resolve).toHaveBeenCalledWith('index-pattern', 'some-index'); + expect(result).toEqual({ isDefaultIndexMigrated: true, defaultIndex: 'some-index' }); + }); + + it('returns the expected result if resolve fails with another error', async () => { + savedObjectsClient.resolve.mockRejectedValue( + SavedObjectsErrorHelpers.createIndexAliasNotFoundError('Oh no!') + ); + const result = await transformDefaultIndex({ + savedObjectsClient, + configAttributes: { defaultIndex: 'some-index' } as UpgradeableConfigAttributes, // We don't care about the other attributes + }); + + expect(savedObjectsClient.resolve).toHaveBeenCalledTimes(1); + expect(savedObjectsClient.resolve).toHaveBeenCalledWith('index-pattern', 'some-index'); + expect(result).toEqual({ isDefaultIndexMigrated: false, defaultIndex: 'some-index' }); + }); + }); +}); diff --git a/src/core/server/ui_settings/saved_objects/transforms.ts b/src/core/server/ui_settings/saved_objects/transforms.ts new file mode 100644 index 00000000000000..cabf14a2e6469e --- /dev/null +++ b/src/core/server/ui_settings/saved_objects/transforms.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { SavedObjectsErrorHelpers } from '../../saved_objects'; +import type { SavedObjectsClientContract } from '../../types'; +import type { UpgradeableConfigAttributes } from '../create_or_upgrade_saved_config'; + +/** + * The params needed to execute each transform function. + */ +interface TransformParams { + savedObjectsClient: SavedObjectsClientContract; + configAttributes: UpgradeableConfigAttributes | undefined; +} + +/** + * The resulting attributes that should be used when upgrading the config object. + * This should be a union of all transform function return types (A | B | C | ...). + */ +type TransformReturnType = TransformDefaultIndexReturnType; + +/** + * The return type for `transformDefaultIndex`. + * If this config object has already been upgraded, it returns `null` because it doesn't need to set different default attributes. + * Otherwise, it always sets a default for the `isDefaultIndexMigrated` attribute, and it optionally sets the `defaultIndex` attribute + * depending on the outcome. + */ +type TransformDefaultIndexReturnType = { + isDefaultIndexMigrated: boolean; + defaultIndex?: string; +} | null; + +export type TransformConfigFn = (params: TransformParams) => Promise; + +/** + * Any transforms that should be applied during `createOrUpgradeSavedConfig` need to be included in this array. + */ +export const transforms: TransformConfigFn[] = [transformDefaultIndex]; + +/** + * This optionally transforms the `defaultIndex` attribute of a config saved object. The `defaultIndex` attribute points to a data view ID, + * but those saved object IDs were regenerated in the 8.0 upgrade. That resulted in a bug where the `defaultIndex` would be broken in custom + * spaces. + * + * We are fixing this bug after the fact in 8.3, and we can't retroactively change a saved object that's already been migrated, so we use + * this transformation instead to ensure that the `defaultIndex` attribute is not broken. + * + * Note that what used to be called "index patterns" prior to 8.0 have been renamed to "data views", but the object type cannot be changed, + * so that type remains `index-pattern`. + * + * Note also that this function is only exported for unit testing. It is also included in the `transforms` export above, which is how it is + * applied during `createOrUpgradeSavedConfig`. + */ +export async function transformDefaultIndex( + params: TransformParams +): Promise { + const { savedObjectsClient, configAttributes } = params; + if (configAttributes?.isDefaultIndexMigrated) { + // This config object has already been migrated, return null because we don't need to set different defaults for the new config object. + return null; + } + if (!configAttributes?.defaultIndex) { + // If configAttributes is undefined (there's no config object being upgraded), OR if configAttributes is defined but the defaultIndex + // attribute is not set, set isDefaultIndexMigrated to true and return. This means there was no defaultIndex to upgrade, so we will just + // avoid attempting to transform this again in the future. + return { isDefaultIndexMigrated: true }; + } + + let defaultIndex = configAttributes.defaultIndex; // Retain the existing defaultIndex attribute in case we run into a resolve error + let isDefaultIndexMigrated: boolean; + try { + // The defaultIndex for this config object was created prior to 8.3, and it might refer to a data view ID that is no longer valid. + // We should try to resolve the data view and change the defaultIndex to the new ID, if necessary. + const resolvedDataView = await savedObjectsClient.resolve('index-pattern', defaultIndex); + if (resolvedDataView.outcome === 'aliasMatch' || resolvedDataView.outcome === 'conflict') { + // This resolved to an aliasMatch or conflict outcome; that means we should change the defaultIndex to the data view's new ID. + // Note, the alias_target_id field is guaranteed to exist iff the resolve outcome is aliasMatch or conflict. + defaultIndex = resolvedDataView.alias_target_id!; + } + isDefaultIndexMigrated = true; // Regardless of the resolve outcome, we now consider this defaultIndex attribute to be migrated + } catch (err) { + // If the defaultIndex is not found at all, it will throw a Not Found error and we should mark the defaultIndex attribute as upgraded. + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + isDefaultIndexMigrated = true; + } else { + // For any other error, explicitly set isDefaultIndexMigrated to false so we can try this upgrade again in the future. + isDefaultIndexMigrated = false; + } + } + return { isDefaultIndexMigrated, defaultIndex }; +} diff --git a/src/core/server/ui_settings/saved_objects/ui_settings.ts b/src/core/server/ui_settings/saved_objects/ui_settings.ts index 9db1402dc2d263..184ec5d41987a1 100644 --- a/src/core/server/ui_settings/saved_objects/ui_settings.ts +++ b/src/core/server/ui_settings/saved_objects/ui_settings.ts @@ -9,6 +9,14 @@ import { SavedObjectsType } from '../../saved_objects'; import { migrations } from './migrations'; +/** + * The `config` object type contains many attributes that are defined by consumers. + */ +export interface ConfigAttributes { + buildNum: number; + [key: string]: unknown; +} + export const uiSettingsType: SavedObjectsType = { name: 'config', hidden: false, diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.test.mock.ts b/src/core/server/ui_settings/ui_settings_client.test.mock.ts similarity index 52% rename from src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.test.mock.ts rename to src/core/server/ui_settings/ui_settings_client.test.mock.ts index cb3fb360befeb4..d2a96352b36ea4 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/get_upgradeable_config.test.mock.ts +++ b/src/core/server/ui_settings/ui_settings_client.test.mock.ts @@ -6,7 +6,11 @@ * Side Public License, v 1. */ -export const getUpgradeableConfigMock = jest.fn(); -jest.doMock('./get_upgradeable_config', () => ({ - getUpgradeableConfig: getUpgradeableConfigMock, +import type { createOrUpgradeSavedConfig } from './create_or_upgrade_saved_config'; + +export const mockCreateOrUpgradeSavedConfig = jest.fn() as jest.MockedFunction< + typeof createOrUpgradeSavedConfig +>; +jest.mock('./create_or_upgrade_saved_config', () => ({ + createOrUpgradeSavedConfig: mockCreateOrUpgradeSavedConfig, })); diff --git a/src/core/server/ui_settings/ui_settings_client.test.ts b/src/core/server/ui_settings/ui_settings_client.test.ts index 99ab87610db90e..844e17e53ab89a 100644 --- a/src/core/server/ui_settings/ui_settings_client.test.ts +++ b/src/core/server/ui_settings/ui_settings_client.test.ts @@ -10,7 +10,7 @@ import Chance from 'chance'; import { schema } from '@kbn/config-schema'; import { loggingSystemMock } from '../logging/logging_system.mock'; -import { createOrUpgradeSavedConfigMock } from './create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.mock'; +import { mockCreateOrUpgradeSavedConfig } from './ui_settings_client.test.mock'; import { SavedObjectsClient } from '../saved_objects'; import { savedObjectsClientMock } from '../saved_objects/service/saved_objects_client.mock'; @@ -47,12 +47,9 @@ describe('ui settings', () => { log: logger, }); - const createOrUpgradeSavedConfig = createOrUpgradeSavedConfigMock; - return { uiSettings, savedObjectsClient, - createOrUpgradeSavedConfig, }; } @@ -84,7 +81,7 @@ describe('ui settings', () => { }); it('automatically creates the savedConfig if it is missing', async () => { - const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup(); + const { uiSettings, savedObjectsClient } = setup(); savedObjectsClient.update .mockRejectedValueOnce(SavedObjectsClient.errors.createGenericNotFoundError()) .mockResolvedValueOnce({} as any); @@ -92,14 +89,14 @@ describe('ui settings', () => { await uiSettings.setMany({ foo: 'bar' }); expect(savedObjectsClient.update).toHaveBeenCalledTimes(2); - expect(createOrUpgradeSavedConfig).toHaveBeenCalledTimes(1); - expect(createOrUpgradeSavedConfig).toHaveBeenCalledWith( + expect(mockCreateOrUpgradeSavedConfig).toHaveBeenCalledTimes(1); + expect(mockCreateOrUpgradeSavedConfig).toHaveBeenCalledWith( expect.objectContaining({ handleWriteErrors: false }) ); }); it('only tried to auto create once and throws NotFound', async () => { - const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup(); + const { uiSettings, savedObjectsClient } = setup(); savedObjectsClient.update.mockRejectedValue( SavedObjectsClient.errors.createGenericNotFoundError() ); @@ -112,8 +109,8 @@ describe('ui settings', () => { } expect(savedObjectsClient.update).toHaveBeenCalledTimes(2); - expect(createOrUpgradeSavedConfig).toHaveBeenCalledTimes(1); - expect(createOrUpgradeSavedConfig).toHaveBeenCalledWith( + expect(mockCreateOrUpgradeSavedConfig).toHaveBeenCalledTimes(1); + expect(mockCreateOrUpgradeSavedConfig).toHaveBeenCalledWith( expect.objectContaining({ handleWriteErrors: false }) ); }); @@ -374,7 +371,7 @@ describe('ui settings', () => { }); it('automatically creates the savedConfig if it is missing and returns empty object', async () => { - const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup(); + const { uiSettings, savedObjectsClient } = setup(); savedObjectsClient.get = jest .fn() .mockRejectedValueOnce(SavedObjectsClient.errors.createGenericNotFoundError()) @@ -384,15 +381,15 @@ describe('ui settings', () => { expect(savedObjectsClient.get).toHaveBeenCalledTimes(2); - expect(createOrUpgradeSavedConfig).toHaveBeenCalledTimes(1); - expect(createOrUpgradeSavedConfig).toHaveBeenCalledWith( + expect(mockCreateOrUpgradeSavedConfig).toHaveBeenCalledTimes(1); + expect(mockCreateOrUpgradeSavedConfig).toHaveBeenCalledWith( expect.objectContaining({ handleWriteErrors: true }) ); }); it('returns result of savedConfig creation in case of notFound error', async () => { - const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup(); - createOrUpgradeSavedConfig.mockResolvedValue({ foo: 'bar ' }); + const { uiSettings, savedObjectsClient } = setup(); + mockCreateOrUpgradeSavedConfig.mockResolvedValue({ foo: 'bar ' }); savedObjectsClient.get.mockRejectedValue( SavedObjectsClient.errors.createGenericNotFoundError() ); @@ -401,23 +398,23 @@ describe('ui settings', () => { }); it('returns an empty object on Forbidden responses', async () => { - const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup(); + const { uiSettings, savedObjectsClient } = setup(); const error = SavedObjectsClient.errors.decorateForbiddenError(new Error()); savedObjectsClient.get.mockRejectedValue(error); expect(await uiSettings.getUserProvided()).toStrictEqual({}); - expect(createOrUpgradeSavedConfig).toHaveBeenCalledTimes(0); + expect(mockCreateOrUpgradeSavedConfig).toHaveBeenCalledTimes(0); }); it('returns an empty object on EsUnavailable responses', async () => { - const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup(); + const { uiSettings, savedObjectsClient } = setup(); const error = SavedObjectsClient.errors.decorateEsUnavailableError(new Error()); savedObjectsClient.get.mockRejectedValue(error); expect(await uiSettings.getUserProvided()).toStrictEqual({}); - expect(createOrUpgradeSavedConfig).toHaveBeenCalledTimes(0); + expect(mockCreateOrUpgradeSavedConfig).toHaveBeenCalledTimes(0); }); it('throws Unauthorized errors', async () => { diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts index b18fed38ef9e4e..1e99e55779a041 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts @@ -12,6 +12,11 @@ import { UsageStats } from './types'; import { REDACTED_KEYWORD } from '../../../common/constants'; import { stackManagementSchema } from './schema'; +/** + * These config keys should be redacted from any usage data, they are only used for implementation details of the config saved object. + */ +const CONFIG_KEYS_TO_REDACT = ['buildNum', 'isDefaultIndexMigrated']; + export function createCollectorFetch(getUiSettingsClient: () => IUiSettingsClient | undefined) { return async function fetchUsageStats(): Promise { const uiSettingsClient = getUiSettingsClient(); @@ -21,7 +26,7 @@ export function createCollectorFetch(getUiSettingsClient: () => IUiSettingsClien const userProvided = await uiSettingsClient.getUserProvided(); const modifiedEntries = Object.entries(userProvided) - .filter(([key]) => key !== 'buildNum') + .filter(([key]) => !CONFIG_KEYS_TO_REDACT.includes(key)) .reduce((obj: Record, [key, { userValue }]) => { const sensitive = uiSettingsClient.isSensitive(key); obj[key] = sensitive ? REDACTED_KEYWORD : userValue; diff --git a/test/functional/apps/discover/_discover_histogram.ts b/test/functional/apps/discover/_discover_histogram.ts index 5932e995421afa..d3d5ea346ddea0 100644 --- a/test/functional/apps/discover/_discover_histogram.ts +++ b/test/functional/apps/discover/_discover_histogram.ts @@ -28,8 +28,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); await esArchiver.load('test/functional/fixtures/es_archiver/long_window_logstash'); - await esArchiver.load( - 'test/functional/fixtures/es_archiver/long_window_logstash_index_pattern' + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/long_window_logstash_index_pattern' ); await security.testUser.setRoles(['kibana_admin', 'long_window_logstash']); await kibanaServer.uiSettings.replace(defaultSettings); @@ -37,9 +37,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); after(async () => { await esArchiver.unload('test/functional/fixtures/es_archiver/long_window_logstash'); - await esArchiver.unload( - 'test/functional/fixtures/es_archiver/long_window_logstash_index_pattern' - ); + await kibanaServer.savedObjects.cleanStandardList(); await security.testUser.restoreDefaults(); await PageObjects.common.unsetTime(); }); diff --git a/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json b/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json index 9998cb3a717327..aea1bf770c18f1 100644 --- a/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json +++ b/test/functional/fixtures/es_archiver/index_pattern_without_timefield/data.json @@ -14,22 +14,6 @@ } } -{ - "type": "doc", - "value": { - "id": "index-pattern:with-timefield", - "index": ".kibana", - "source": { - "index-pattern": { - "fields": "[]", - "title": "with-timefield", - "timeFieldName": "@timestamp" - }, - "type": "index-pattern" - } - } -} - { "type": "doc", "value": { diff --git a/test/functional/fixtures/es_archiver/long_window_logstash_index_pattern/data.json b/test/functional/fixtures/es_archiver/long_window_logstash_index_pattern/data.json deleted file mode 100644 index 75aa6f06bb11a6..00000000000000 --- a/test/functional/fixtures/es_archiver/long_window_logstash_index_pattern/data.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "type": "doc", - "value": { - "id": "index-pattern:long-window-logstash-*", - "index": ".kibana", - "source": { - "index-pattern": { - "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", - "timeFieldName": "@timestamp", - "title": "long-window-logstash-*" - }, - "type": "index-pattern" - } - } -} - - diff --git a/test/functional/fixtures/kbn_archiver/long_window_logstash_index_pattern.json b/test/functional/fixtures/kbn_archiver/long_window_logstash_index_pattern.json new file mode 100644 index 00000000000000..379e15fe0d7fe1 --- /dev/null +++ b/test/functional/fixtures/kbn_archiver/long_window_logstash_index_pattern.json @@ -0,0 +1,31 @@ +{ + "attributes": { + "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", + "timeFieldName": "@timestamp", + "title": "long-window-logstash-*" + }, + "coreMigrationVersion": "8.4.0", + "id": "long-window-logstash-*", + "migrationVersion": { + "index-pattern": "8.0.0" + }, + "references": [], + "type": "index-pattern", + "version": "WzE3LDJd" +} + +{ + "attributes": { + "fields": "[]", + "timeFieldName": "@timestamp", + "title": "with-timefield" + }, + "coreMigrationVersion": "8.4.0", + "id": "with-timefield", + "migrationVersion": { + "index-pattern": "8.0.0" + }, + "references": [], + "type": "index-pattern", + "version": "WzE1LDJd" +} \ No newline at end of file diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts index 7c465c81873095..a2ef3b988cf19f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts @@ -70,11 +70,12 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm - tar xzvf elastic-agent--x86_64.rpm - cd elastic-agent--x86_64 + sudo rpm -vi elastic-agent--x86_64.rpm sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1" + --fleet-server-service-token=service-token-1 + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" `); }); @@ -87,11 +88,12 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb - tar xzvf elastic-agent--amd64.deb - cd elastic-agent--amd64 + sudo dpkg -i elastic-agent--amd64.deb sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ - --fleet-server-service-token=service-token-1" + --fleet-server-service-token=service-token-1 + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" `); }); @@ -187,12 +189,13 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm - tar xzvf elastic-agent--x86_64.rpm - cd elastic-agent--x86_64 + sudo rpm -vi elastic-agent--x86_64.rpm sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ - --fleet-server-policy=policy-1" + --fleet-server-policy=policy-1 + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" `); }); @@ -206,12 +209,13 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb - tar xzvf elastic-agent--amd64.deb - cd elastic-agent--amd64 + sudo dpkg -i elastic-agent--amd64.deb sudo elastic-agent enroll \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ - --fleet-server-policy=policy-1" + --fleet-server-policy=policy-1 + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" `); }); }); @@ -305,8 +309,7 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--x86_64.rpm - tar xzvf elastic-agent--x86_64.rpm - cd elastic-agent--x86_64 + sudo rpm -vi elastic-agent--x86_64.rpm sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ @@ -314,7 +317,9 @@ describe('getInstallCommandForPlatform', () => { --certificate-authorities= \\\\ --fleet-server-es-ca= \\\\ --fleet-server-cert= \\\\ - --fleet-server-cert-key=" + --fleet-server-cert-key= + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" `); }); @@ -330,8 +335,7 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--amd64.deb - tar xzvf elastic-agent--amd64.deb - cd elastic-agent--amd64 + sudo dpkg -i elastic-agent--amd64.deb sudo elastic-agent enroll --url=http://fleetserver:8220 \\\\ --fleet-server-es=http://elasticsearch:9200 \\\\ --fleet-server-service-token=service-token-1 \\\\ @@ -339,7 +343,9 @@ describe('getInstallCommandForPlatform', () => { --certificate-authorities= \\\\ --fleet-server-es-ca= \\\\ --fleet-server-cert= \\\\ - --fleet-server-cert-key=" + --fleet-server-cert-key= + sudo systemctl enable elastic-agent + sudo systemctl start elastic-agent" `); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts index 183a93dcede934..14cb60d76991f5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts @@ -14,34 +14,40 @@ export type CommandsByPlatform = { function getArtifact(platform: PLATFORM_TYPE, kibanaVersion: string) { const ARTIFACT_BASE_URL = 'https://artifacts.elastic.co/downloads/beats/elastic-agent'; - const artifactMap: Record< - PLATFORM_TYPE, - { fullUrl: string; filename: string; unpackedDir: string } - > = { + const artifactMap: Record = { linux: { - fullUrl: `${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-linux-x86_64.tar.gz`, - filename: `elastic-agent-${kibanaVersion}-linux-x86_64.tar.gz`, - unpackedDir: `elastic-agent-${kibanaVersion}-linux-x86_64`, + downloadCommand: [ + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-linux-x86_64.tar.gz`, + `tar xzvf elastic-agent-${kibanaVersion}-linux-x86_64.tar.gz`, + `cd elastic-agent-${kibanaVersion}-linux-x86_64`, + ].join(`\n`), }, mac: { - fullUrl: `${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-darwin-x86_64.tar.gz`, - filename: `elastic-agent-${kibanaVersion}-darwin-x86_64.tar.gz`, - unpackedDir: `elastic-agent-${kibanaVersion}-darwin-x86_64`, + downloadCommand: [ + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-darwin-x86_64.tar.gz`, + `tar xzvf elastic-agent-${kibanaVersion}-darwin-x86_64.tar.gz`, + `cd elastic-agent-${kibanaVersion}-darwin-x86_64`, + ].join(`\n`), }, windows: { - fullUrl: `${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-windows-x86_64.zip`, - filename: `elastic-agent-${kibanaVersion}-windows-x86_64.zip`, - unpackedDir: `elastic-agent-${kibanaVersion}-windows-x86_64`, + downloadCommand: [ + `$ProgressPreference = 'SilentlyContinue'`, + `wget ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-windows-x86_64.zip -OutFile elastic-agent-${kibanaVersion}-windows-x86_64.zip`, + `Expand-Archive .\\elastic-agent-${kibanaVersion}-windows-x86_64.zip`, + `cd elastic-agent-${kibanaVersion}-windows-x86_64`, + ].join(`\n`), }, deb: { - fullUrl: `${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-amd64.deb`, - filename: `elastic-agent-${kibanaVersion}-amd64.deb`, - unpackedDir: `elastic-agent-${kibanaVersion}-amd64`, + downloadCommand: [ + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-amd64.deb`, + `sudo dpkg -i elastic-agent-${kibanaVersion}-amd64.deb`, + ].join(`\n`), }, rpm: { - fullUrl: `${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-x86_64.rpm`, - filename: `elastic-agent-${kibanaVersion}-x86_64.rpm`, - unpackedDir: `elastic-agent-${kibanaVersion}-x86_64`, + downloadCommand: [ + `curl -L -O ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-x86_64.rpm`, + `sudo rpm -vi elastic-agent-${kibanaVersion}-x86_64.rpm`, + ].join(`\n`), }, }; @@ -61,19 +67,6 @@ export function getInstallCommandForPlatform( const newLineSeparator = platform === 'windows' ? '`\n' : '\\\n'; const artifact = getArtifact(platform, kibanaVersion ?? ''); - const downloadCommand = - platform === 'windows' - ? [ - "$ProgressPreference = 'SilentlyContinue'", - `wget ${artifact.fullUrl} -OutFile ${artifact.filename}`, - `Expand-Archive .\\${artifact.filename}`, - `cd ${artifact.unpackedDir}`, - ].join(`\n`) - : [ - `curl -L -O ${artifact.fullUrl}`, - `tar xzvf ${artifact.filename}`, - `cd ${artifact.unpackedDir}`, - ].join(`\n`); const commandArguments = []; @@ -109,11 +102,11 @@ export function getInstallCommandForPlatform( }, ''); const commands = { - linux: `${downloadCommand}\nsudo ./elastic-agent install${commandArgumentsStr}`, - mac: `${downloadCommand}\nsudo ./elastic-agent install ${commandArgumentsStr}`, - windows: `${downloadCommand}\n.\\elastic-agent.exe install ${commandArgumentsStr}`, - deb: `${downloadCommand}\nsudo elastic-agent enroll ${commandArgumentsStr}`, - rpm: `${downloadCommand}\nsudo elastic-agent enroll ${commandArgumentsStr}`, + linux: `${artifact.downloadCommand}\nsudo ./elastic-agent install${commandArgumentsStr}`, + mac: `${artifact.downloadCommand}\nsudo ./elastic-agent install ${commandArgumentsStr}`, + windows: `${artifact.downloadCommand}\n.\\elastic-agent.exe install ${commandArgumentsStr}`, + deb: `${artifact.downloadCommand}\nsudo elastic-agent enroll ${commandArgumentsStr}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent`, + rpm: `${artifact.downloadCommand}\nsudo elastic-agent enroll ${commandArgumentsStr}\nsudo systemctl enable elastic-agent\nsudo systemctl start elastic-agent`, }; return commands[platform]; diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx index 24d8def12bbdcd..97c0542ab2477d 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx @@ -70,6 +70,8 @@ export const Instructions = (props: InstructionProps) => { return settings?.fleet_server_hosts || []; }, [settings]); + if (isLoadingAgents || isLoadingAgentPolicies) return ; + const hasNoFleetServerHost = fleetStatus.isReady && fleetServerHosts.length === 0; const showAgentEnrollment = @@ -89,8 +91,6 @@ export const Instructions = (props: InstructionProps) => { setSelectionType('tabs'); } - if (isLoadingAgents || isLoadingAgentPolicies) return ; - if (hasNoFleetServerHost) { return null; }