mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Add a default 'User-Agent' HTTP header (#141631)
(cherry picked from commit 681e2b5c72
)
Co-authored-by: Seth Michael Larson <seth.larson@elastic.co>
This commit is contained in:
parent
172f7aa68a
commit
cf881f8cf7
10 changed files with 214 additions and 76 deletions
|
@ -15,5 +15,6 @@ export {
|
|||
PRODUCT_RESPONSE_HEADER,
|
||||
DEFAULT_HEADERS,
|
||||
PRODUCT_ORIGIN_HEADER,
|
||||
USER_AGENT_HEADER,
|
||||
RESERVED_HEADERS,
|
||||
} from './src/headers';
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { duration } from 'moment';
|
||||
import type { ElasticsearchClientConfig } from '@kbn/core-elasticsearch-server';
|
||||
import { parseClientOptions } from './client_config';
|
||||
import { DEFAULT_HEADERS } from './headers';
|
||||
import { getDefaultHeaders } from './headers';
|
||||
|
||||
const createConfig = (
|
||||
parts: Partial<ElasticsearchClientConfig> = {}
|
||||
|
@ -27,15 +27,16 @@ const createConfig = (
|
|||
};
|
||||
};
|
||||
|
||||
const kibanaVersion = '1.0.0';
|
||||
const defaultHeaders = getDefaultHeaders(kibanaVersion);
|
||||
|
||||
describe('parseClientOptions', () => {
|
||||
it('includes headers designing the HTTP request as originating from Kibana by default', () => {
|
||||
const config = createConfig({});
|
||||
|
||||
expect(parseClientOptions(config, false)).toEqual(
|
||||
expect(parseClientOptions(config, false, kibanaVersion)).toEqual(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
},
|
||||
headers: defaultHeaders,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -43,7 +44,7 @@ describe('parseClientOptions', () => {
|
|||
it('specifies `headers.maxSockets` Infinity and `keepAlive` true by default', () => {
|
||||
const config = createConfig({});
|
||||
|
||||
expect(parseClientOptions(config, false)).toEqual(
|
||||
expect(parseClientOptions(config, false, kibanaVersion)).toEqual(
|
||||
expect.objectContaining({
|
||||
agent: {
|
||||
keepAlive: true,
|
||||
|
@ -62,10 +63,10 @@ describe('parseClientOptions', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(parseClientOptions(config, false)).toEqual(
|
||||
expect(parseClientOptions(config, false, kibanaVersion)).toEqual(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...defaultHeaders,
|
||||
foo: 'bar',
|
||||
hello: 'dolly',
|
||||
},
|
||||
|
@ -74,16 +75,20 @@ describe('parseClientOptions', () => {
|
|||
});
|
||||
|
||||
it('`customHeaders` take precedence to default kibana headers', () => {
|
||||
const customHeader = {
|
||||
[Object.keys(DEFAULT_HEADERS)[0]]: 'foo',
|
||||
};
|
||||
const customHeader: Record<string, string> = {};
|
||||
for (const header in defaultHeaders) {
|
||||
if (defaultHeaders.hasOwnProperty(header)) {
|
||||
customHeader[header] = 'foo';
|
||||
}
|
||||
}
|
||||
|
||||
const config = createConfig({
|
||||
customHeaders: {
|
||||
...customHeader,
|
||||
},
|
||||
});
|
||||
|
||||
expect(parseClientOptions(config, false)).toEqual(
|
||||
expect(parseClientOptions(config, false, kibanaVersion)).toEqual(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...customHeader,
|
||||
|
@ -94,41 +99,57 @@ describe('parseClientOptions', () => {
|
|||
|
||||
describe('`keepAlive` option', () => {
|
||||
it('`keepAlive` is true', () => {
|
||||
const options = parseClientOptions(createConfig({ keepAlive: true }), false);
|
||||
const options = parseClientOptions(createConfig({ keepAlive: true }), false, kibanaVersion);
|
||||
expect(options.agent).toHaveProperty('keepAlive', true);
|
||||
});
|
||||
|
||||
it('`keepAlive` is false', () => {
|
||||
const options = parseClientOptions(createConfig({ keepAlive: false }), false);
|
||||
const options = parseClientOptions(
|
||||
createConfig({ keepAlive: false }),
|
||||
false,
|
||||
kibanaVersion
|
||||
);
|
||||
expect(options.agent).toHaveProperty('keepAlive', false);
|
||||
});
|
||||
|
||||
it('`keepAlive` is undefined', () => {
|
||||
const options = parseClientOptions(createConfig({}), false);
|
||||
const options = parseClientOptions(createConfig({}), false, kibanaVersion);
|
||||
expect(options.agent).toHaveProperty('keepAlive', true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('`maxSockets` option', () => {
|
||||
it('uses the specified config value', () => {
|
||||
const options = parseClientOptions(createConfig({ maxSockets: 1024 }), false);
|
||||
const options = parseClientOptions(
|
||||
createConfig({ maxSockets: 1024 }),
|
||||
false,
|
||||
kibanaVersion
|
||||
);
|
||||
expect(options.agent).toHaveProperty('maxSockets', 1024);
|
||||
});
|
||||
|
||||
it('defaults to `Infinity` if not specified by the config', () => {
|
||||
const options = parseClientOptions(createConfig({}), false);
|
||||
const options = parseClientOptions(createConfig({}), false, kibanaVersion);
|
||||
expect(options.agent).toHaveProperty('maxSockets', Infinity);
|
||||
});
|
||||
});
|
||||
|
||||
describe('`compression` option', () => {
|
||||
it('`compression` is true', () => {
|
||||
const options = parseClientOptions(createConfig({ compression: true }), false);
|
||||
const options = parseClientOptions(
|
||||
createConfig({ compression: true }),
|
||||
false,
|
||||
kibanaVersion
|
||||
);
|
||||
expect(options.compression).toBe(true);
|
||||
});
|
||||
|
||||
it('`compression` is false', () => {
|
||||
const options = parseClientOptions(createConfig({ compression: false }), false);
|
||||
const options = parseClientOptions(
|
||||
createConfig({ compression: false }),
|
||||
false,
|
||||
kibanaVersion
|
||||
);
|
||||
expect(options.compression).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -139,7 +160,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
sniffOnStart: true,
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).sniffOnStart
|
||||
).toEqual(true);
|
||||
|
||||
|
@ -148,7 +170,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
sniffOnStart: false,
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).sniffOnStart
|
||||
).toEqual(false);
|
||||
});
|
||||
|
@ -158,7 +181,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
sniffOnConnectionFault: true,
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).sniffOnConnectionFault
|
||||
).toEqual(true);
|
||||
|
||||
|
@ -167,7 +191,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
sniffOnConnectionFault: false,
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).sniffOnConnectionFault
|
||||
).toEqual(false);
|
||||
});
|
||||
|
@ -177,7 +202,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
sniffInterval: false,
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).sniffInterval
|
||||
).toEqual(false);
|
||||
|
||||
|
@ -186,7 +212,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
sniffInterval: duration(100, 'ms'),
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).sniffInterval
|
||||
).toEqual(100);
|
||||
});
|
||||
|
@ -196,7 +223,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
hosts: ['http://node-A:9200', 'http://node-B', 'https://node-C'],
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
);
|
||||
|
||||
expect(options.nodes).toMatchInlineSnapshot(`
|
||||
|
@ -215,7 +243,11 @@ describe('parseClientOptions', () => {
|
|||
});
|
||||
|
||||
it('`caFingerprint` option', () => {
|
||||
const options = parseClientOptions(createConfig({ caFingerprint: 'ab:cd:ef' }), false);
|
||||
const options = parseClientOptions(
|
||||
createConfig({ caFingerprint: 'ab:cd:ef' }),
|
||||
false,
|
||||
kibanaVersion
|
||||
);
|
||||
|
||||
expect(options.caFingerprint).toBe('ab:cd:ef');
|
||||
});
|
||||
|
@ -229,7 +261,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
username: 'user',
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).auth
|
||||
).toBeUndefined();
|
||||
|
||||
|
@ -238,7 +271,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
password: 'pass',
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).auth
|
||||
).toBeUndefined();
|
||||
|
||||
|
@ -248,7 +282,8 @@ describe('parseClientOptions', () => {
|
|||
username: 'user',
|
||||
password: 'pass',
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
)
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
|
@ -266,7 +301,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
serviceAccountToken: 'ABC123',
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
)
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
|
@ -283,7 +319,8 @@ describe('parseClientOptions', () => {
|
|||
serviceAccountToken: 'ABC123',
|
||||
hosts: ['http://node-A:9200'],
|
||||
}),
|
||||
true
|
||||
true,
|
||||
kibanaVersion
|
||||
);
|
||||
expect(options.nodes).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -302,7 +339,8 @@ describe('parseClientOptions', () => {
|
|||
username: 'user',
|
||||
password: 'pass',
|
||||
}),
|
||||
true
|
||||
true,
|
||||
kibanaVersion
|
||||
).auth
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
@ -314,7 +352,8 @@ describe('parseClientOptions', () => {
|
|||
password: 'pass',
|
||||
hosts: ['http://node-A:9200'],
|
||||
}),
|
||||
true
|
||||
true,
|
||||
kibanaVersion
|
||||
);
|
||||
expect(options.nodes).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -331,7 +370,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
serviceAccountToken: 'ABC123',
|
||||
}),
|
||||
true
|
||||
true,
|
||||
kibanaVersion
|
||||
).headers
|
||||
).not.toHaveProperty('authorization');
|
||||
});
|
||||
|
@ -342,7 +382,8 @@ describe('parseClientOptions', () => {
|
|||
serviceAccountToken: 'ABC123',
|
||||
hosts: ['http://node-A:9200'],
|
||||
}),
|
||||
true
|
||||
true,
|
||||
kibanaVersion
|
||||
);
|
||||
expect(options.nodes).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -357,8 +398,8 @@ describe('parseClientOptions', () => {
|
|||
|
||||
describe('tls config', () => {
|
||||
it('does not generate tls option is ssl config is not set', () => {
|
||||
expect(parseClientOptions(createConfig({}), false).tls).toBeUndefined();
|
||||
expect(parseClientOptions(createConfig({}), true).tls).toBeUndefined();
|
||||
expect(parseClientOptions(createConfig({}), false, kibanaVersion).tls).toBeUndefined();
|
||||
expect(parseClientOptions(createConfig({}), true, kibanaVersion).tls).toBeUndefined();
|
||||
});
|
||||
|
||||
it('handles the `certificateAuthorities` option', () => {
|
||||
|
@ -367,7 +408,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
ssl: { verificationMode: 'full', certificateAuthorities: ['content-of-ca-path'] },
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls!.ca
|
||||
).toEqual(['content-of-ca-path']);
|
||||
expect(
|
||||
|
@ -375,7 +417,8 @@ describe('parseClientOptions', () => {
|
|||
createConfig({
|
||||
ssl: { verificationMode: 'full', certificateAuthorities: ['content-of-ca-path'] },
|
||||
}),
|
||||
true
|
||||
true,
|
||||
kibanaVersion
|
||||
).tls!.ca
|
||||
).toEqual(['content-of-ca-path']);
|
||||
});
|
||||
|
@ -389,7 +432,8 @@ describe('parseClientOptions', () => {
|
|||
verificationMode: 'none',
|
||||
},
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -406,7 +450,8 @@ describe('parseClientOptions', () => {
|
|||
verificationMode: 'certificate',
|
||||
},
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -424,7 +469,8 @@ describe('parseClientOptions', () => {
|
|||
verificationMode: 'full',
|
||||
},
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -442,7 +488,8 @@ describe('parseClientOptions', () => {
|
|||
verificationMode: 'unknown' as any,
|
||||
},
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Unknown ssl verificationMode: unknown"`);
|
||||
});
|
||||
|
@ -455,7 +502,8 @@ describe('parseClientOptions', () => {
|
|||
verificationMode: undefined as any,
|
||||
},
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Unknown ssl verificationMode: undefined"`);
|
||||
});
|
||||
|
@ -472,7 +520,8 @@ describe('parseClientOptions', () => {
|
|||
keyPassphrase: 'passphrase',
|
||||
},
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -492,7 +541,8 @@ describe('parseClientOptions', () => {
|
|||
keyPassphrase: 'passphrase',
|
||||
},
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -513,7 +563,8 @@ describe('parseClientOptions', () => {
|
|||
keyPassphrase: 'passphrase',
|
||||
},
|
||||
}),
|
||||
false
|
||||
false,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -537,7 +588,8 @@ describe('parseClientOptions', () => {
|
|||
keyPassphrase: 'passphrase',
|
||||
},
|
||||
}),
|
||||
true
|
||||
true,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -557,7 +609,8 @@ describe('parseClientOptions', () => {
|
|||
alwaysPresentCertificate: true,
|
||||
},
|
||||
}),
|
||||
true
|
||||
true,
|
||||
kibanaVersion
|
||||
).tls
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { URL } from 'url';
|
|||
import { Duration } from 'moment';
|
||||
import type { ClientOptions, HttpAgentOptions } from '@elastic/elasticsearch';
|
||||
import type { ElasticsearchClientConfig } from '@kbn/core-elasticsearch-server';
|
||||
import { DEFAULT_HEADERS } from './headers';
|
||||
import { getDefaultHeaders } from './headers';
|
||||
|
||||
export type ParsedClientOptions = Omit<ClientOptions, 'agent'> & { agent: HttpAgentOptions };
|
||||
|
||||
|
@ -24,13 +24,14 @@ export type ParsedClientOptions = Omit<ClientOptions, 'agent'> & { agent: HttpAg
|
|||
*/
|
||||
export function parseClientOptions(
|
||||
config: ElasticsearchClientConfig,
|
||||
scoped: boolean
|
||||
scoped: boolean,
|
||||
kibanaVersion: string
|
||||
): ParsedClientOptions {
|
||||
const clientOptions: ParsedClientOptions = {
|
||||
sniffOnStart: config.sniffOnStart,
|
||||
sniffOnConnectionFault: config.sniffOnConnectionFault,
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...getDefaultHeaders(kibanaVersion),
|
||||
...config.customHeaders,
|
||||
},
|
||||
// do not make assumption on user-supplied data content
|
||||
|
|
|
@ -16,7 +16,7 @@ import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
|||
import { httpServerMock, httpServiceMock } from '@kbn/core-http-server-mocks';
|
||||
import type { ElasticsearchClientConfig } from '@kbn/core-elasticsearch-server';
|
||||
import { ClusterClient } from './cluster_client';
|
||||
import { DEFAULT_HEADERS } from './headers';
|
||||
import { DEFAULT_HEADERS, getDefaultHeaders } from './headers';
|
||||
import { AgentManager } from './agent_manager';
|
||||
|
||||
const createConfig = (
|
||||
|
@ -35,6 +35,9 @@ const createConfig = (
|
|||
};
|
||||
};
|
||||
|
||||
const kibanaVersion = '1.0.0';
|
||||
const defaultHeaders = getDefaultHeaders(kibanaVersion);
|
||||
|
||||
const createClient = () =>
|
||||
({ close: jest.fn(), child: jest.fn() } as unknown as jest.Mocked<Client>);
|
||||
|
||||
|
@ -82,18 +85,21 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
getExecutionContext: getExecutionContextMock,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(configureClientMock).toHaveBeenCalledTimes(2);
|
||||
expect(configureClientMock).toHaveBeenCalledWith(config, {
|
||||
logger,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
type: 'custom-type',
|
||||
getExecutionContext: getExecutionContextMock,
|
||||
});
|
||||
expect(configureClientMock).toHaveBeenCalledWith(config, {
|
||||
logger,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
type: 'custom-type',
|
||||
getExecutionContext: getExecutionContextMock,
|
||||
scoped: true,
|
||||
|
@ -108,6 +114,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(clusterClient.asInternalUser).toBe(internalClient);
|
||||
|
@ -122,6 +129,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
|
@ -148,6 +156,7 @@ describe('ClusterClient', () => {
|
|||
getExecutionContext,
|
||||
getUnauthorizedErrorHandler,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
|
@ -171,6 +180,7 @@ describe('ClusterClient', () => {
|
|||
getExecutionContext,
|
||||
getUnauthorizedErrorHandler,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
|
@ -203,6 +213,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
|
@ -227,6 +238,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
headers: {
|
||||
|
@ -240,7 +252,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: { ...DEFAULT_HEADERS, foo: 'bar', 'x-opaque-id': expect.any(String) },
|
||||
headers: { ...defaultHeaders, foo: 'bar', 'x-opaque-id': expect.any(String) },
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -260,6 +272,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({});
|
||||
|
||||
|
@ -269,7 +282,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...defaultHeaders,
|
||||
authorization: 'auth',
|
||||
other: 'yep',
|
||||
'x-opaque-id': expect.any(String),
|
||||
|
@ -293,6 +306,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
headers: {
|
||||
|
@ -306,7 +320,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...defaultHeaders,
|
||||
authorization: 'auth',
|
||||
other: 'yep',
|
||||
'x-opaque-id': expect.any(String),
|
||||
|
@ -331,6 +345,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({});
|
||||
|
||||
|
@ -340,7 +355,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...defaultHeaders,
|
||||
foo: 'bar',
|
||||
hello: 'dolly',
|
||||
'x-opaque-id': expect.any(String),
|
||||
|
@ -359,6 +374,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
kibanaRequestState: { requestId: 'my-fake-id', requestUuid: 'ignore-this-id' },
|
||||
|
@ -370,7 +386,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...defaultHeaders,
|
||||
'x-opaque-id': 'my-fake-id',
|
||||
},
|
||||
})
|
||||
|
@ -395,6 +411,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({});
|
||||
|
||||
|
@ -404,7 +421,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...defaultHeaders,
|
||||
foo: 'auth',
|
||||
hello: 'dolly',
|
||||
'x-opaque-id': expect.any(String),
|
||||
|
@ -429,6 +446,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
headers: { foo: 'request' },
|
||||
|
@ -440,7 +458,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...defaultHeaders,
|
||||
foo: 'request',
|
||||
hello: 'dolly',
|
||||
'x-opaque-id': expect.any(String),
|
||||
|
@ -453,6 +471,7 @@ describe('ClusterClient', () => {
|
|||
const headerKey = Object.keys(DEFAULT_HEADERS)[0];
|
||||
const config = createConfig({
|
||||
customHeaders: {
|
||||
...defaultHeaders,
|
||||
[headerKey]: 'foo',
|
||||
},
|
||||
});
|
||||
|
@ -464,6 +483,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
|
@ -473,6 +493,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...defaultHeaders,
|
||||
[headerKey]: 'foo',
|
||||
'x-opaque-id': expect.any(String),
|
||||
},
|
||||
|
@ -493,6 +514,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
headers: { [headerKey]: 'foo' },
|
||||
|
@ -504,6 +526,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...defaultHeaders,
|
||||
[headerKey]: 'foo',
|
||||
'x-opaque-id': expect.any(String),
|
||||
},
|
||||
|
@ -525,6 +548,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
headers: { foo: 'request' },
|
||||
|
@ -537,7 +561,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...defaultHeaders,
|
||||
'x-opaque-id': 'from request',
|
||||
},
|
||||
})
|
||||
|
@ -556,6 +580,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = {
|
||||
headers: {
|
||||
|
@ -569,7 +594,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: { ...DEFAULT_HEADERS, authorization: 'auth' },
|
||||
headers: { ...defaultHeaders, authorization: 'auth' },
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -588,6 +613,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
const request = {
|
||||
headers: {
|
||||
|
@ -601,7 +627,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
headers: { ...DEFAULT_HEADERS, foo: 'bar' },
|
||||
headers: { ...defaultHeaders, foo: 'bar' },
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -615,6 +641,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
await clusterClient.close();
|
||||
|
@ -632,6 +659,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
let internalClientClosed = false;
|
||||
|
@ -676,6 +704,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
internalClient.close.mockRejectedValue(new Error('error closing client'));
|
||||
|
@ -692,6 +721,7 @@ describe('ClusterClient', () => {
|
|||
type: 'custom-type',
|
||||
authHeaders,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
await clusterClient.close();
|
||||
|
|
|
@ -23,7 +23,7 @@ import type {
|
|||
import type { ElasticsearchClientConfig } from '@kbn/core-elasticsearch-server';
|
||||
import { configureClient } from './configure_client';
|
||||
import { ScopedClusterClient } from './scoped_cluster_client';
|
||||
import { DEFAULT_HEADERS } from './headers';
|
||||
import { getDefaultHeaders } from './headers';
|
||||
import { createInternalErrorHandler, InternalUnauthorizedErrorHandler } from './retry_unauthorized';
|
||||
import { createTransport } from './create_transport';
|
||||
import { AgentManager } from './agent_manager';
|
||||
|
@ -35,6 +35,7 @@ export class ClusterClient implements ICustomClusterClient {
|
|||
private readonly config: ElasticsearchClientConfig;
|
||||
private readonly authHeaders?: IAuthHeadersStorage;
|
||||
private readonly rootScopedClient: Client;
|
||||
private readonly kibanaVersion: string;
|
||||
private readonly getUnauthorizedErrorHandler: () => UnauthorizedErrorHandler | undefined;
|
||||
private readonly getExecutionContext: () => string | undefined;
|
||||
private isClosed = false;
|
||||
|
@ -49,6 +50,7 @@ export class ClusterClient implements ICustomClusterClient {
|
|||
getExecutionContext = noop,
|
||||
getUnauthorizedErrorHandler = noop,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
}: {
|
||||
config: ElasticsearchClientConfig;
|
||||
logger: Logger;
|
||||
|
@ -57,9 +59,11 @@ export class ClusterClient implements ICustomClusterClient {
|
|||
getExecutionContext?: () => string | undefined;
|
||||
getUnauthorizedErrorHandler?: () => UnauthorizedErrorHandler | undefined;
|
||||
agentManager: AgentManager;
|
||||
kibanaVersion: string;
|
||||
}) {
|
||||
this.config = config;
|
||||
this.authHeaders = authHeaders;
|
||||
this.kibanaVersion = kibanaVersion;
|
||||
this.getExecutionContext = getExecutionContext;
|
||||
this.getUnauthorizedErrorHandler = getUnauthorizedErrorHandler;
|
||||
|
||||
|
@ -68,6 +72,7 @@ export class ClusterClient implements ICustomClusterClient {
|
|||
type,
|
||||
getExecutionContext,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
this.rootScopedClient = configureClient(config, {
|
||||
logger,
|
||||
|
@ -75,6 +80,7 @@ export class ClusterClient implements ICustomClusterClient {
|
|||
getExecutionContext,
|
||||
scoped: true,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -132,7 +138,7 @@ export class ClusterClient implements ICustomClusterClient {
|
|||
}
|
||||
|
||||
return {
|
||||
...DEFAULT_HEADERS,
|
||||
...getDefaultHeaders(this.kibanaVersion),
|
||||
...this.config.customHeaders,
|
||||
...scopedHeaders,
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@ import { instrumentEsQueryAndDeprecationLogger } from './log_query_and_deprecati
|
|||
import { AgentManager } from './agent_manager';
|
||||
|
||||
const AgentManagerMock = AgentManager as jest.Mock<AgentManager>;
|
||||
const kibanaVersion = '1.0.0';
|
||||
|
||||
const createFakeConfig = (
|
||||
parts: Partial<ElasticsearchClientConfig> = {}
|
||||
|
@ -79,17 +80,17 @@ describe('configureClient', () => {
|
|||
});
|
||||
|
||||
it('calls `parseClientOptions` with the correct parameters', () => {
|
||||
configureClient(config, { logger, type: 'test', scoped: false, agentManager });
|
||||
configureClient(config, { logger, type: 'test', scoped: false, agentManager, kibanaVersion });
|
||||
|
||||
expect(parseClientOptionsMock).toHaveBeenCalledTimes(1);
|
||||
expect(parseClientOptionsMock).toHaveBeenCalledWith(config, false);
|
||||
expect(parseClientOptionsMock).toHaveBeenCalledWith(config, false, kibanaVersion);
|
||||
|
||||
parseClientOptionsMock.mockClear();
|
||||
|
||||
configureClient(config, { logger, type: 'test', scoped: true, agentManager });
|
||||
configureClient(config, { logger, type: 'test', scoped: true, agentManager, kibanaVersion });
|
||||
|
||||
expect(parseClientOptionsMock).toHaveBeenCalledTimes(1);
|
||||
expect(parseClientOptionsMock).toHaveBeenCalledWith(config, true);
|
||||
expect(parseClientOptionsMock).toHaveBeenCalledWith(config, true, kibanaVersion);
|
||||
});
|
||||
|
||||
it('constructs a client using the options returned by `parseClientOptions`', () => {
|
||||
|
@ -98,7 +99,13 @@ describe('configureClient', () => {
|
|||
};
|
||||
parseClientOptionsMock.mockReturnValue(parsedOptions);
|
||||
|
||||
const client = configureClient(config, { logger, type: 'test', scoped: false, agentManager });
|
||||
const client = configureClient(config, {
|
||||
logger,
|
||||
type: 'test',
|
||||
scoped: false,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(ClientMock).toHaveBeenCalledTimes(1);
|
||||
expect(ClientMock).toHaveBeenCalledWith(expect.objectContaining(parsedOptions));
|
||||
|
@ -112,6 +119,7 @@ describe('configureClient', () => {
|
|||
type: 'test',
|
||||
scoped: false,
|
||||
agentManager: customAgentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(ClientMock).toHaveBeenCalledTimes(1);
|
||||
|
@ -127,6 +135,7 @@ describe('configureClient', () => {
|
|||
scoped: false,
|
||||
getExecutionContext,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(createTransportMock).toHaveBeenCalledTimes(1);
|
||||
|
@ -140,6 +149,7 @@ describe('configureClient', () => {
|
|||
scoped: true,
|
||||
getExecutionContext,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(createTransportMock).toHaveBeenCalledTimes(1);
|
||||
|
@ -150,7 +160,13 @@ describe('configureClient', () => {
|
|||
const mockedTransport = { mockTransport: true };
|
||||
createTransportMock.mockReturnValue(mockedTransport);
|
||||
|
||||
const client = configureClient(config, { logger, type: 'test', scoped: false, agentManager });
|
||||
const client = configureClient(config, {
|
||||
logger,
|
||||
type: 'test',
|
||||
scoped: false,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(ClientMock).toHaveBeenCalledTimes(1);
|
||||
expect(ClientMock).toHaveBeenCalledWith(
|
||||
|
@ -165,7 +181,13 @@ describe('configureClient', () => {
|
|||
const mockedTransport = { mockTransport: true };
|
||||
createTransportMock.mockReturnValue(mockedTransport);
|
||||
|
||||
const client = configureClient(config, { logger, type: 'test', scoped: false, agentManager });
|
||||
const client = configureClient(config, {
|
||||
logger,
|
||||
type: 'test',
|
||||
scoped: false,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(ClientMock).toHaveBeenCalledTimes(1);
|
||||
expect(ClientMock).toHaveBeenCalledWith(
|
||||
|
@ -177,7 +199,13 @@ describe('configureClient', () => {
|
|||
});
|
||||
|
||||
it('calls instrumentEsQueryAndDeprecationLogger', () => {
|
||||
const client = configureClient(config, { logger, type: 'test', scoped: false, agentManager });
|
||||
const client = configureClient(config, {
|
||||
logger,
|
||||
type: 'test',
|
||||
scoped: false,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(instrumentEsQueryAndDeprecationLogger).toHaveBeenCalledTimes(1);
|
||||
expect(instrumentEsQueryAndDeprecationLogger).toHaveBeenCalledWith({
|
||||
|
|
|
@ -24,15 +24,17 @@ export const configureClient = (
|
|||
scoped = false,
|
||||
getExecutionContext = noop,
|
||||
agentManager,
|
||||
kibanaVersion,
|
||||
}: {
|
||||
logger: Logger;
|
||||
type: string;
|
||||
scoped?: boolean;
|
||||
getExecutionContext?: () => string | undefined;
|
||||
agentManager: AgentManager;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
): Client => {
|
||||
const clientOptions = parseClientOptions(config, scoped);
|
||||
const clientOptions = parseClientOptions(config, scoped, kibanaVersion);
|
||||
const KibanaTransport = createTransport({ getExecutionContext });
|
||||
const client = new Client({
|
||||
...clientOptions,
|
||||
|
|
|
@ -21,7 +21,12 @@ export const PRODUCT_ORIGIN_HEADER = 'x-elastic-product-origin';
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const RESERVED_HEADERS = deepFreeze([PRODUCT_ORIGIN_HEADER]);
|
||||
export const USER_AGENT_HEADER = 'user-agent';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const RESERVED_HEADERS = deepFreeze([PRODUCT_ORIGIN_HEADER, USER_AGENT_HEADER]);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
@ -31,3 +36,13 @@ export const DEFAULT_HEADERS = deepFreeze({
|
|||
// access system indices using the standard ES APIs.
|
||||
[PRODUCT_ORIGIN_HEADER]: 'kibana',
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function getDefaultHeaders(kibanaVersion: string) {
|
||||
return {
|
||||
...DEFAULT_HEADERS,
|
||||
[USER_AGENT_HEADER]: `Kibana/${kibanaVersion}`,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -183,6 +183,7 @@ export class ElasticsearchService
|
|||
getExecutionContext: () => this.executionContextClient?.getAsHeader(),
|
||||
getUnauthorizedErrorHandler: () => this.unauthorizedErrorHandler,
|
||||
agentManager: this.agentManager,
|
||||
kibanaVersion: this.kibanaVersion,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ export const elasticsearch = new ElasticsearchService(logger, kibanaPackageJson.
|
|||
type,
|
||||
// we use an independent AgentManager for cli_setup, no need to track performance of this one
|
||||
agentManager: new AgentManager(),
|
||||
kibanaVersion: kibanaPackageJson.version,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue