Skip to content

Commit 1f04c2d

Browse files
Merge branch 'master' into ml-feature-importance-functional-tests
2 parents 6549088 + 50efaec commit 1f04c2d

84 files changed

Lines changed: 3108 additions & 470 deletions

File tree

Some content is hidden

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

docs/developer/architecture/security/feature-registration.asciidoc

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,10 @@ server.route({
198198
=== Example 3: Discover
199199

200200
Discover takes advantage of subfeature privileges to allow fine-grained access control. In this example,
201-
a single "Create Short URLs" subfeature privilege is defined, which allows users to grant access to this feature without having to grant the `all` privilege to Discover. In other words, you can grant `read` access to Discover, and also grant the ability to create short URLs.
201+
two subfeature privileges are defined: "Create Short URLs", and "Generate PDF Reports". These allow users to grant access to this feature without having to grant the `all` privilege to Discover. In other words, you can grant `read` access to Discover, and also grant the ability to create short URLs or generate PDF reports.
202+
203+
Notice the "Generate PDF Reports" subfeature privilege has an additional `minimumPrivilege` option. Kibana will only offer this subfeature privilege if the
204+
license requirement is satisfied.
202205

203206
["source","javascript"]
204207
-----------
@@ -259,6 +262,28 @@ public setup(core, { features }) {
259262
},
260263
],
261264
},
265+
{
266+
groupType: 'independent',
267+
privileges: [
268+
{
269+
id: 'pdf_generate',
270+
name: i18n.translate(
271+
'xpack.features.ossFeatures.discoverGeneratePDFReportsPrivilegeName',
272+
{
273+
defaultMessage: 'Generate PDF Reports',
274+
}
275+
),
276+
minimumLicense: 'platinum',
277+
includeIn: 'all',
278+
savedObject: {
279+
all: [],
280+
read: [],
281+
},
282+
api: ['generatePDFReports'],
283+
ui: ['generatePDFReports'],
284+
},
285+
],
286+
},
262287
],
263288
},
264289
],

docs/getting-started/quick-start-guide.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,4 @@ For more information, refer to <<lens, *Lens*>>.
140140

141141
If you are you ready to add your own data, refer to <<connect-to-elasticsearch,Add data to {kib}>>.
142142

143-
If you want to ingest your data, refer to {ingest-guide}/ingest-management-getting-started.html[Quick start: Get logs and metrics into the Elastic Stack].
143+
If you want to ingest your data, refer to {ingest-guide}/fleet-quick-start.html[Quick start: Get logs and metrics into the Elastic Stack].

docs/setup/connect-to-elasticsearch.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ ship with dashboards and visualizations,
3737
so you can quickly get insights into your data.
3838

3939
To get started, refer to
40-
{ingest-guide}/ingest-management-getting-started.html[Quick start: Get logs and metrics into the Elastic Stack].
40+
{ingest-guide}/fleet-quick-start.html[Quick start: Get logs and metrics into the Elastic Stack].
4141

4242
[role="screenshot"]
4343
image::images/add-data-fleet.png[Add data using Fleet]

src/dev/build/tasks/os_packages/package_scripts/post_install.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ set_chmod() {
1717

1818
set_chown() {
1919
chown <%= user %>:<%= group %> <%= logDir %>
20+
chown <%= user %>:<%= group %> <%= pidDir %>
2021
chown -R <%= user %>:<%= group %> <%= dataDir %>
2122
chown -R root:<%= group %> ${KBN_PATH_CONF}
2223
}

src/dev/build/tasks/os_packages/run_fpm.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ export async function runFpm(
112112
'--template-value',
113113
`logDir=/var/log/kibana`,
114114
'--template-value',
115+
`pidDir=/run/kibana`,
116+
'--template-value',
115117
`envFile=/etc/default/kibana`,
116118
// config and data directories are copied to /usr/share and /var/lib
117119
// below, so exclude them from the main package source located in
@@ -120,6 +122,8 @@ export async function runFpm(
120122
`usr/share/kibana/config`,
121123
'--exclude',
122124
`usr/share/kibana/data`,
125+
'--exclude',
126+
'run/kibana/.gitempty',
123127

124128
// flags specific to the package we are building, supplied by tasks below
125129
...pkgSpecificFlags,

src/dev/build/tasks/os_packages/service_templates/systemd/run/kibana/.gitempty

Whitespace-only changes.

x-pack/plugins/data_enhanced/common/search/es_search/es_search_rxjs_utils.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
*/
66

77
import { of, merge, timer, throwError } from 'rxjs';
8-
import { takeWhile, switchMap, expand, mergeMap, tap } from 'rxjs/operators';
8+
import { map, takeWhile, switchMap, expand, mergeMap, tap } from 'rxjs/operators';
9+
import { ApiResponse } from '@elastic/elasticsearch';
910

1011
import {
1112
doSearch,
@@ -35,6 +36,15 @@ export const doPartialSearch = <SearchResponse = any>(
3536
takeWhile((response) => !isCompleteResponse(response), true)
3637
);
3738

39+
export const normalizeEqlResponse = <SearchResponse extends ApiResponse = ApiResponse>() =>
40+
map<SearchResponse, SearchResponse>((eqlResponse) => ({
41+
...eqlResponse,
42+
body: {
43+
...eqlResponse.body,
44+
...eqlResponse,
45+
},
46+
}));
47+
3848
export const throwOnEsError = () =>
3949
mergeMap((r: IKibanaSearchResponse) =>
4050
isErrorResponse(r) ? merge(of(r), throwError(new AbortError())) : of(r)

x-pack/plugins/data_enhanced/server/search/eql_search_strategy.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const getMockEqlResponse = () => ({
2222
sequences: [],
2323
},
2424
},
25+
meta: {},
26+
statusCode: 200,
2527
});
2628

2729
describe('EQL search strategy', () => {
@@ -193,5 +195,20 @@ describe('EQL search strategy', () => {
193195
expect(requestOptions).toEqual(expect.objectContaining({ ignore: [400] }));
194196
});
195197
});
198+
199+
describe('response', () => {
200+
it('contains a rawResponse field containing the full search response', async () => {
201+
const eqlSearch = await eqlSearchStrategyProvider(mockLogger);
202+
const response = await eqlSearch
203+
.search({ id: 'my-search-id', options: { ignore: [400] } }, {}, mockDeps)
204+
.toPromise();
205+
206+
expect(response).toEqual(
207+
expect.objectContaining({
208+
rawResponse: expect.objectContaining(getMockEqlResponse()),
209+
})
210+
);
211+
});
212+
});
196213
});
197214
});

x-pack/plugins/data_enhanced/server/search/eql_search_strategy.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import type { Logger } from 'kibana/server';
88
import type { ApiResponse } from '@elastic/elasticsearch';
99

1010
import { search } from '../../../../../src/plugins/data/server';
11-
import { doPartialSearch } from '../../common/search/es_search/es_search_rxjs_utils';
11+
import {
12+
doPartialSearch,
13+
normalizeEqlResponse,
14+
} from '../../common/search/es_search/es_search_rxjs_utils';
1215
import { getAsyncOptions, getDefaultSearchParams } from './get_default_search_params';
1316

1417
import type { ISearchStrategy, IEsRawSearchResponse } from '../../../../../src/plugins/data/server';
@@ -64,7 +67,7 @@ export const eqlSearchStrategyProvider = (
6467
(response) => response.body.id,
6568
request.id,
6669
options
67-
).pipe(utils.toKibanaSearchResponse());
70+
).pipe(normalizeEqlResponse(), utils.toKibanaSearchResponse());
6871
},
6972
};
7073
};
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { resetContext } from 'kea';
8+
9+
import { mockHttpValues } from '../../../__mocks__';
10+
jest.mock('../../../shared/http', () => ({
11+
HttpLogic: { values: mockHttpValues },
12+
}));
13+
const { http } = mockHttpValues;
14+
15+
jest.mock('../../../shared/flash_messages', () => ({
16+
flashAPIErrors: jest.fn(),
17+
}));
18+
import { flashAPIErrors } from '../../../shared/flash_messages';
19+
20+
jest.mock('../engine', () => ({
21+
EngineLogic: { values: { engineName: 'some-engine' } },
22+
}));
23+
24+
import { EngineOverviewLogic } from './';
25+
26+
describe('EngineOverviewLogic', () => {
27+
const mockEngineMetrics = {
28+
apiLogsUnavailable: true,
29+
documentCount: 10,
30+
startDate: '1970-01-30',
31+
endDate: '1970-01-31',
32+
operationsPerDay: [0, 0, 0, 0, 0, 0, 0],
33+
queriesPerDay: [0, 0, 0, 0, 0, 25, 50],
34+
totalClicks: 50,
35+
totalQueries: 75,
36+
};
37+
38+
const DEFAULT_VALUES = {
39+
dataLoading: true,
40+
apiLogsUnavailable: false,
41+
documentCount: 0,
42+
startDate: '',
43+
endDate: '',
44+
operationsPerDay: [],
45+
queriesPerDay: [],
46+
totalClicks: 0,
47+
totalQueries: 0,
48+
timeoutId: null,
49+
};
50+
51+
const mount = () => {
52+
resetContext({});
53+
EngineOverviewLogic.mount();
54+
};
55+
56+
beforeEach(() => {
57+
jest.clearAllMocks();
58+
});
59+
60+
it('has expected default values', () => {
61+
mount();
62+
expect(EngineOverviewLogic.values).toEqual(DEFAULT_VALUES);
63+
});
64+
65+
describe('actions', () => {
66+
describe('setPolledData', () => {
67+
it('should set all received data as top-level values and set dataLoading to false', () => {
68+
mount();
69+
EngineOverviewLogic.actions.setPolledData(mockEngineMetrics);
70+
71+
expect(EngineOverviewLogic.values).toEqual({
72+
...DEFAULT_VALUES,
73+
...mockEngineMetrics,
74+
dataLoading: false,
75+
});
76+
});
77+
});
78+
79+
describe('setTimeoutId', () => {
80+
describe('timeoutId', () => {
81+
it('should be set to the provided value', () => {
82+
mount();
83+
EngineOverviewLogic.actions.setTimeoutId(123);
84+
85+
expect(EngineOverviewLogic.values).toEqual({
86+
...DEFAULT_VALUES,
87+
timeoutId: 123,
88+
});
89+
});
90+
});
91+
});
92+
93+
describe('pollForOverviewMetrics', () => {
94+
it('fetches data and calls onPollingSuccess', async () => {
95+
mount();
96+
jest.spyOn(EngineOverviewLogic.actions, 'onPollingSuccess');
97+
const promise = Promise.resolve(mockEngineMetrics);
98+
http.get.mockReturnValueOnce(promise);
99+
100+
EngineOverviewLogic.actions.pollForOverviewMetrics();
101+
await promise;
102+
103+
expect(http.get).toHaveBeenCalledWith('/api/app_search/engines/some-engine/overview');
104+
expect(EngineOverviewLogic.actions.onPollingSuccess).toHaveBeenCalledWith(
105+
mockEngineMetrics
106+
);
107+
});
108+
109+
it('handles errors', async () => {
110+
mount();
111+
const promise = Promise.reject('An error occurred');
112+
http.get.mockReturnValue(promise);
113+
114+
try {
115+
EngineOverviewLogic.actions.pollForOverviewMetrics();
116+
await promise;
117+
} catch {
118+
// Do nothing
119+
}
120+
expect(flashAPIErrors).toHaveBeenCalledWith('An error occurred');
121+
});
122+
});
123+
124+
describe('onPollingSuccess', () => {
125+
it('starts a polling timeout and sets data', async () => {
126+
mount();
127+
jest.useFakeTimers();
128+
jest.spyOn(EngineOverviewLogic.actions, 'setTimeoutId');
129+
jest.spyOn(EngineOverviewLogic.actions, 'setPolledData');
130+
131+
EngineOverviewLogic.actions.onPollingSuccess(mockEngineMetrics);
132+
133+
expect(setTimeout).toHaveBeenCalledWith(
134+
EngineOverviewLogic.actions.pollForOverviewMetrics,
135+
5000
136+
);
137+
expect(EngineOverviewLogic.actions.setTimeoutId).toHaveBeenCalledWith(expect.any(Number));
138+
expect(EngineOverviewLogic.actions.setPolledData).toHaveBeenCalledWith(mockEngineMetrics);
139+
});
140+
});
141+
});
142+
143+
describe('unmount', () => {
144+
let unmount: Function;
145+
146+
beforeEach(() => {
147+
jest.useFakeTimers();
148+
resetContext({});
149+
unmount = EngineOverviewLogic.mount();
150+
});
151+
152+
it('clears existing polling timeouts on unmount', () => {
153+
EngineOverviewLogic.actions.setTimeoutId(123);
154+
unmount();
155+
expect(clearTimeout).toHaveBeenCalled();
156+
});
157+
158+
it("does not clear timeout if one hasn't been set", () => {
159+
unmount();
160+
expect(clearTimeout).not.toHaveBeenCalled();
161+
});
162+
});
163+
});

0 commit comments

Comments
 (0)