Skip to content

Commit 79a3760

Browse files
Merge branch 'master' into auto_fit_to_bounds2
2 parents 0f78615 + f331cc8 commit 79a3760

File tree

91 files changed

+2646
-1591
lines changed

Some content is hidden

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

91 files changed

+2646
-1591
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@
322322
"@types/browserslist-useragent": "^3.0.0",
323323
"@types/chance": "^1.0.0",
324324
"@types/cheerio": "^0.22.10",
325-
"@types/chromedriver": "^2.38.0",
325+
"@types/chromedriver": "^81.0.0",
326326
"@types/classnames": "^2.2.9",
327327
"@types/color": "^3.0.0",
328328
"@types/d3": "^3.5.43",
@@ -411,7 +411,7 @@
411411
"chai": "3.5.0",
412412
"chance": "1.0.18",
413413
"cheerio": "0.22.0",
414-
"chromedriver": "^83.0.0",
414+
"chromedriver": "^84.0.0",
415415
"classnames": "2.2.6",
416416
"dedent": "^0.7.0",
417417
"delete-empty": "^2.0.0",

src/core/public/index.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
@import './chrome/index';
33
@import './overlays/index';
44
@import './rendering/index';
5+
@import './styles/index';
56

6-
// Global styles need to be migrated
7-
@import '../../legacy/ui/public/styles/_legacy/_index';
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
@import '@elastic/eui/src/components/call_out/variables';
2-
@import '@elastic/eui/src/components/call_out/mixins';
3-
41
// SASSTODO: Replace with an EUI editor
52
// Intentionally not using the EuiCodeBlock colors here because they actually change
63
// hue from light to dark theme. So some colors would change while others wouldn't.
@@ -181,7 +178,7 @@
181178
}
182179

183180
&.ace_multiselect .ace_selection.ace_start {
184-
box-shadow: 0 0 3px 0px $euiColorEmptyShade;
181+
box-shadow: 0 0 3px 0 $euiColorEmptyShade;
185182
}
186183

187184
.ace_marker-layer .ace_step {

src/core/public/styles/_base.scss

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
@import '@elastic/eui/src/components/collapsible_nav/variables';
2+
// Application Layout
3+
4+
// chrome-context
5+
// TODO #64541
6+
// Delete this block
7+
.chrHeaderWrapper:not(.headerWrapper) .content {
8+
display: flex;
9+
flex-flow: row nowrap;
10+
width: 100%;
11+
height: 100%;
12+
overflow: hidden;
13+
}
14+
15+
.application,
16+
.app-container {
17+
> * {
18+
position: relative;
19+
}
20+
}
21+
22+
.application {
23+
position: relative;
24+
z-index: 0;
25+
display: flex;
26+
flex-grow: 1;
27+
flex-shrink: 0;
28+
flex-basis: auto;
29+
flex-direction: column;
30+
31+
> * {
32+
flex-shrink: 0;
33+
}
34+
}
35+
36+
// We apply brute force focus states to anything not coming from Eui
37+
// which has focus states designed at the component level.
38+
// You can also use "kbn-resetFocusState" to not apply the default focus
39+
// state. This is useful when you've already hand crafted your own
40+
// focus states in Kibana.
41+
:focus {
42+
&:not([class^='eui']):not(.kbn-resetFocusState) {
43+
@include euiFocusRing;
44+
}
45+
}
46+
47+
// A necessary hack so that the above focus policy doesn't pollute some EUI
48+
// entrenched inputs.
49+
.euiComboBox {
50+
// :not() specificity needed to override the above
51+
input:not([class^='eui']):focus {
52+
animation: none !important;
53+
}
54+
}
55+
56+
.euiBody--collapsibleNavIsDocked .euiBottomBar {
57+
margin-left: $euiCollapsibleNavWidth;
58+
}

src/core/public/styles/_index.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@import './base';
2+
@import './ace_overrides';

src/core/server/elasticsearch/client/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ export { IScopedClusterClient, ScopedClusterClient } from './scoped_cluster_clie
2222
export { ElasticsearchClientConfig } from './client_config';
2323
export { IClusterClient, ICustomClusterClient, ClusterClient } from './cluster_client';
2424
export { configureClient } from './configure_client';
25+
export { retryCallCluster, migrationRetryCallCluster } from './retry_call_cluster';
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { errors } from '@elastic/elasticsearch';
21+
import { elasticsearchClientMock } from './mocks';
22+
import { loggingSystemMock } from '../../logging/logging_system.mock';
23+
import { retryCallCluster, migrationRetryCallCluster } from './retry_call_cluster';
24+
25+
const dummyBody = { foo: 'bar' };
26+
const createErrorReturn = (err: any) => elasticsearchClientMock.createClientError(err);
27+
28+
describe('retryCallCluster', () => {
29+
let client: ReturnType<typeof elasticsearchClientMock.createElasticSearchClient>;
30+
31+
beforeEach(() => {
32+
client = elasticsearchClientMock.createElasticSearchClient();
33+
});
34+
35+
it('returns response from ES API call in case of success', async () => {
36+
const successReturn = elasticsearchClientMock.createClientResponse({ ...dummyBody });
37+
38+
client.asyncSearch.get.mockReturnValue(successReturn);
39+
40+
const result = await retryCallCluster(() => client.asyncSearch.get());
41+
expect(result.body).toEqual(dummyBody);
42+
});
43+
44+
it('retries ES API calls that rejects with `NoLivingConnectionsError`', async () => {
45+
const successReturn = elasticsearchClientMock.createClientResponse({ ...dummyBody });
46+
47+
client.asyncSearch.get
48+
.mockImplementationOnce(() =>
49+
createErrorReturn(new errors.NoLivingConnectionsError('no living connections', {} as any))
50+
)
51+
.mockImplementationOnce(() => successReturn);
52+
53+
const result = await retryCallCluster(() => client.asyncSearch.get());
54+
expect(result.body).toEqual(dummyBody);
55+
});
56+
57+
it('rejects when ES API calls reject with other errors', async () => {
58+
client.ping
59+
.mockImplementationOnce(() => createErrorReturn(new Error('unknown error')))
60+
.mockImplementationOnce(() => elasticsearchClientMock.createClientResponse({ ...dummyBody }));
61+
62+
await expect(retryCallCluster(() => client.ping())).rejects.toMatchInlineSnapshot(
63+
`[Error: unknown error]`
64+
);
65+
});
66+
67+
it('stops retrying when ES API calls reject with other errors', async () => {
68+
client.ping
69+
.mockImplementationOnce(() =>
70+
createErrorReturn(new errors.NoLivingConnectionsError('no living connections', {} as any))
71+
)
72+
.mockImplementationOnce(() =>
73+
createErrorReturn(new errors.NoLivingConnectionsError('no living connections', {} as any))
74+
)
75+
.mockImplementationOnce(() => createErrorReturn(new Error('unknown error')))
76+
.mockImplementationOnce(() => elasticsearchClientMock.createClientResponse({ ...dummyBody }));
77+
78+
await expect(retryCallCluster(() => client.ping())).rejects.toMatchInlineSnapshot(
79+
`[Error: unknown error]`
80+
);
81+
});
82+
});
83+
84+
describe('migrationRetryCallCluster', () => {
85+
let client: ReturnType<typeof elasticsearchClientMock.createElasticSearchClient>;
86+
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
87+
88+
beforeEach(() => {
89+
client = elasticsearchClientMock.createElasticSearchClient();
90+
logger = loggingSystemMock.createLogger();
91+
});
92+
93+
const mockClientPingWithErrorBeforeSuccess = (error: any) => {
94+
client.ping
95+
.mockImplementationOnce(() => createErrorReturn(error))
96+
.mockImplementationOnce(() => createErrorReturn(error))
97+
.mockImplementationOnce(() => elasticsearchClientMock.createClientResponse({ ...dummyBody }));
98+
};
99+
100+
it('retries ES API calls that rejects with `NoLivingConnectionsError`', async () => {
101+
mockClientPingWithErrorBeforeSuccess(
102+
new errors.NoLivingConnectionsError('no living connections', {} as any)
103+
);
104+
105+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
106+
expect(result.body).toEqual(dummyBody);
107+
});
108+
109+
it('retries ES API calls that rejects with `ConnectionError`', async () => {
110+
mockClientPingWithErrorBeforeSuccess(new errors.ConnectionError('connection error', {} as any));
111+
112+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
113+
expect(result.body).toEqual(dummyBody);
114+
});
115+
116+
it('retries ES API calls that rejects with `TimeoutError`', async () => {
117+
mockClientPingWithErrorBeforeSuccess(new errors.TimeoutError('timeout error', {} as any));
118+
119+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
120+
expect(result.body).toEqual(dummyBody);
121+
});
122+
123+
it('retries ES API calls that rejects with 503 `ResponseError`', async () => {
124+
mockClientPingWithErrorBeforeSuccess(
125+
new errors.ResponseError({
126+
statusCode: 503,
127+
} as any)
128+
);
129+
130+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
131+
expect(result.body).toEqual(dummyBody);
132+
});
133+
134+
it('retries ES API calls that rejects 401 `ResponseError`', async () => {
135+
mockClientPingWithErrorBeforeSuccess(
136+
new errors.ResponseError({
137+
statusCode: 401,
138+
} as any)
139+
);
140+
141+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
142+
expect(result.body).toEqual(dummyBody);
143+
});
144+
145+
it('retries ES API calls that rejects with 403 `ResponseError`', async () => {
146+
mockClientPingWithErrorBeforeSuccess(
147+
new errors.ResponseError({
148+
statusCode: 403,
149+
} as any)
150+
);
151+
152+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
153+
expect(result.body).toEqual(dummyBody);
154+
});
155+
156+
it('retries ES API calls that rejects with 408 `ResponseError`', async () => {
157+
mockClientPingWithErrorBeforeSuccess(
158+
new errors.ResponseError({
159+
statusCode: 408,
160+
} as any)
161+
);
162+
163+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
164+
expect(result.body).toEqual(dummyBody);
165+
});
166+
167+
it('retries ES API calls that rejects with 410 `ResponseError`', async () => {
168+
mockClientPingWithErrorBeforeSuccess(
169+
new errors.ResponseError({
170+
statusCode: 410,
171+
} as any)
172+
);
173+
174+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
175+
expect(result.body).toEqual(dummyBody);
176+
});
177+
178+
it('retries ES API calls that rejects with `snapshot_in_progress_exception` `ResponseError`', async () => {
179+
mockClientPingWithErrorBeforeSuccess(
180+
new errors.ResponseError({
181+
statusCode: 500,
182+
body: {
183+
error: {
184+
type: 'snapshot_in_progress_exception',
185+
},
186+
},
187+
} as any)
188+
);
189+
190+
const result = await migrationRetryCallCluster(() => client.ping(), logger, 1);
191+
expect(result.body).toEqual(dummyBody);
192+
});
193+
194+
it('logs only once for each unique error message', async () => {
195+
client.ping
196+
.mockImplementationOnce(() =>
197+
createErrorReturn(
198+
new errors.ResponseError({
199+
statusCode: 503,
200+
} as any)
201+
)
202+
)
203+
.mockImplementationOnce(() =>
204+
createErrorReturn(new errors.ConnectionError('connection error', {} as any))
205+
)
206+
.mockImplementationOnce(() =>
207+
createErrorReturn(
208+
new errors.ResponseError({
209+
statusCode: 503,
210+
} as any)
211+
)
212+
)
213+
.mockImplementationOnce(() =>
214+
createErrorReturn(new errors.ConnectionError('connection error', {} as any))
215+
)
216+
.mockImplementationOnce(() =>
217+
createErrorReturn(
218+
new errors.ResponseError({
219+
statusCode: 500,
220+
body: {
221+
error: {
222+
type: 'snapshot_in_progress_exception',
223+
},
224+
},
225+
} as any)
226+
)
227+
)
228+
.mockImplementationOnce(() => elasticsearchClientMock.createClientResponse({ ...dummyBody }));
229+
230+
await migrationRetryCallCluster(() => client.ping(), logger, 1);
231+
232+
expect(loggingSystemMock.collect(logger).warn).toMatchInlineSnapshot(`
233+
Array [
234+
Array [
235+
"Unable to connect to Elasticsearch. Error: Response Error",
236+
],
237+
Array [
238+
"Unable to connect to Elasticsearch. Error: connection error",
239+
],
240+
Array [
241+
"Unable to connect to Elasticsearch. Error: snapshot_in_progress_exception",
242+
],
243+
]
244+
`);
245+
});
246+
247+
it('rejects when ES API calls reject with other errors', async () => {
248+
client.ping
249+
.mockImplementationOnce(() =>
250+
createErrorReturn(
251+
new errors.ResponseError({
252+
statusCode: 418,
253+
body: {
254+
error: {
255+
type: `I'm a teapot`,
256+
},
257+
},
258+
} as any)
259+
)
260+
)
261+
.mockImplementationOnce(() => elasticsearchClientMock.createClientResponse({ ...dummyBody }));
262+
263+
await expect(
264+
migrationRetryCallCluster(() => client.ping(), logger, 1)
265+
).rejects.toMatchInlineSnapshot(`[ResponseError: I'm a teapot]`);
266+
});
267+
268+
it('stops retrying when ES API calls reject with other errors', async () => {
269+
client.ping
270+
.mockImplementationOnce(() =>
271+
createErrorReturn(new errors.TimeoutError('timeout error', {} as any))
272+
)
273+
.mockImplementationOnce(() =>
274+
createErrorReturn(new errors.TimeoutError('timeout error', {} as any))
275+
)
276+
.mockImplementationOnce(() => createErrorReturn(new Error('unknown error')))
277+
.mockImplementationOnce(() => elasticsearchClientMock.createClientResponse({ ...dummyBody }));
278+
279+
await expect(
280+
migrationRetryCallCluster(() => client.ping(), logger, 1)
281+
).rejects.toMatchInlineSnapshot(`[Error: unknown error]`);
282+
});
283+
});

0 commit comments

Comments
 (0)