mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Config Service] Expose serverless
contextRef (#156837)
This commit is contained in:
parent
1506cb2aef
commit
ff6943376d
8 changed files with 207 additions and 9 deletions
|
@ -147,3 +147,64 @@ export const config: PluginConfigDescriptor<ConfigType> = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
----
|
----
|
||||||
|
[[validating-your-configuration-based-on-context-references]]
|
||||||
|
=== Validating your configuration based on context references
|
||||||
|
Some features require special configuration when running in different modes (dev/prod/dist, or even serverless). For purpose, core injects the following _references_ in the validation's context:
|
||||||
|
|
||||||
|
[cols="^1,^1,3"]
|
||||||
|
|===
|
||||||
|
|Context Reference |Potential values |Description
|
||||||
|
|
||||||
|
|`dev`
|
||||||
|
|`true`\|`false`
|
||||||
|
|Is Kibana running in Dev mode?
|
||||||
|
|
||||||
|
|`prod`
|
||||||
|
|`true`\|`false`
|
||||||
|
|Is Kibana running in Production mode (running from binary)?
|
||||||
|
|
||||||
|
|`dist`
|
||||||
|
|`true`\|`false`
|
||||||
|
|Is Kibana running from a distributable build (not running from source)?
|
||||||
|
|
||||||
|
|`serverless`
|
||||||
|
|`true`\|`false`
|
||||||
|
|Is Kibana running in Serverless offering?
|
||||||
|
|
||||||
|
|`version`
|
||||||
|
|`8.9.0`
|
||||||
|
|The current version of Kibana
|
||||||
|
|
||||||
|
|`buildNum`
|
||||||
|
|`12345`
|
||||||
|
|The build number
|
||||||
|
|
||||||
|
|`branch`
|
||||||
|
|`main`
|
||||||
|
|The current branch running
|
||||||
|
|
||||||
|
|`buildSha`
|
||||||
|
|`12345`
|
||||||
|
|The build SHA (typically refers to the last commit's SHA)
|
||||||
|
|
||||||
|
|===
|
||||||
|
|
||||||
|
To use any of the references listed above in a config validation schema, they can be accessed via `schema.contextRef('{CONTEXT_REFERENCE}')`:
|
||||||
|
|
||||||
|
[source,js]
|
||||||
|
----
|
||||||
|
export const config = {
|
||||||
|
schema: schema.object({
|
||||||
|
// Enabled by default in Dev mode
|
||||||
|
enabled: schema.boolean({ defaultValue: schema.contextRef('dev') }),
|
||||||
|
|
||||||
|
// Setting only allowed in the Serverless offering
|
||||||
|
plansForWorldPeace: schema.conditional(
|
||||||
|
schema.contextRef('serverless'),
|
||||||
|
true,
|
||||||
|
schema.string({ defaultValue: 'Free hugs' }),
|
||||||
|
schema.never()
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
----
|
||||||
|
|
|
@ -154,7 +154,8 @@ export const configSchema = schema.object({
|
||||||
return '"ignoreVersionMismatch" can only be set to true in development mode';
|
return '"ignoreVersionMismatch" can only be set to true in development mode';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
defaultValue: false,
|
// When running in serverless mode, default to `true`
|
||||||
|
defaultValue: schema.contextRef('serverless'),
|
||||||
}),
|
}),
|
||||||
schema.boolean({ defaultValue: false })
|
schema.boolean({ defaultValue: false })
|
||||||
),
|
),
|
||||||
|
|
|
@ -97,8 +97,7 @@ export class ElasticsearchService
|
||||||
const esNodesCompatibility$ = pollEsNodesVersion({
|
const esNodesCompatibility$ = pollEsNodesVersion({
|
||||||
internalClient: this.client.asInternalUser,
|
internalClient: this.client.asInternalUser,
|
||||||
log: this.log,
|
log: this.log,
|
||||||
ignoreVersionMismatch:
|
ignoreVersionMismatch: config.ignoreVersionMismatch,
|
||||||
config.ignoreVersionMismatch || this.coreContext.env.cliArgs.serverless === true,
|
|
||||||
esVersionCheckInterval: config.healthCheckDelay.asMilliseconds(),
|
esVersionCheckInterval: config.healthCheckDelay.asMilliseconds(),
|
||||||
kibanaVersion: this.kibanaVersion,
|
kibanaVersion: this.kibanaVersion,
|
||||||
}).pipe(takeUntil(this.stop$), shareReplay({ refCount: true, bufferSize: 1 }));
|
}).pipe(takeUntil(this.stop$), shareReplay({ refCount: true, bufferSize: 1 }));
|
||||||
|
|
|
@ -197,7 +197,7 @@ export interface TestKibanaUtils {
|
||||||
|
|
||||||
export interface TestUtils {
|
export interface TestUtils {
|
||||||
startES: () => Promise<TestElasticsearchUtils>;
|
startES: () => Promise<TestElasticsearchUtils>;
|
||||||
startKibana: () => Promise<TestKibanaUtils>;
|
startKibana: (abortSignal?: AbortSignal) => Promise<TestKibanaUtils>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -261,7 +261,7 @@ export function createTestServers({
|
||||||
// Add time for KBN and adding users
|
// Add time for KBN and adding users
|
||||||
adjustTimeout(es.getStartTimeout() + 100000);
|
adjustTimeout(es.getStartTimeout() + 100000);
|
||||||
|
|
||||||
const kbnSettings = settings.kbn ?? {};
|
const { cliArgs = {}, customKibanaVersion, ...kbnSettings } = settings.kbn ?? {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
startES: async () => {
|
startES: async () => {
|
||||||
|
@ -284,8 +284,10 @@ export function createTestServers({
|
||||||
password: kibanaServerTestUser.password,
|
password: kibanaServerTestUser.password,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
startKibana: async () => {
|
startKibana: async (abortSignal?: AbortSignal) => {
|
||||||
const root = createRootWithCorePlugins(kbnSettings);
|
const root = createRootWithCorePlugins(kbnSettings, cliArgs, customKibanaVersion);
|
||||||
|
|
||||||
|
abortSignal?.addEventListener('abort', async () => await root.shutdown());
|
||||||
|
|
||||||
await root.preboot();
|
await root.preboot();
|
||||||
const coreSetup = await root.setup();
|
const coreSetup = await root.setup();
|
||||||
|
|
|
@ -241,6 +241,7 @@ export class ConfigService {
|
||||||
{
|
{
|
||||||
dev: this.env.mode.dev,
|
dev: this.env.mode.dev,
|
||||||
prod: this.env.mode.prod,
|
prod: this.env.mode.prod,
|
||||||
|
serverless: this.env.cliArgs.serverless === true,
|
||||||
...this.env.packageInfo,
|
...this.env.packageInfo,
|
||||||
},
|
},
|
||||||
`config validation of [${namespace}]`
|
`config validation of [${namespace}]`
|
||||||
|
|
|
@ -56,7 +56,7 @@ export interface CreateTestEsClusterOptions {
|
||||||
clusterName?: string;
|
clusterName?: string;
|
||||||
/**
|
/**
|
||||||
* Path to data archive snapshot to run Elasticsearch with.
|
* Path to data archive snapshot to run Elasticsearch with.
|
||||||
* To prepare the the snapshot:
|
* To prepare the snapshot:
|
||||||
* - run Elasticsearch server
|
* - run Elasticsearch server
|
||||||
* - index necessary data
|
* - index necessary data
|
||||||
* - stop Elasticsearch server
|
* - stop Elasticsearch server
|
||||||
|
|
|
@ -68,7 +68,6 @@ function createFakeElasticsearchServer() {
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FLAKY: https://github.com/elastic/kibana/issues/129754
|
|
||||||
describe('fake elasticsearch', () => {
|
describe('fake elasticsearch', () => {
|
||||||
let esServer: http.Server;
|
let esServer: http.Server;
|
||||||
let kibanaServer: Root;
|
let kibanaServer: Root;
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
createTestServers,
|
||||||
|
type TestElasticsearchUtils,
|
||||||
|
type TestKibanaUtils,
|
||||||
|
} from '@kbn/core-test-helpers-kbn-server';
|
||||||
|
import { esTestConfig } from '@kbn/test';
|
||||||
|
import { firstValueFrom, Subject } from 'rxjs';
|
||||||
|
import { CliArgs } from '@kbn/config';
|
||||||
|
import Semver from 'semver';
|
||||||
|
|
||||||
|
function nextMinor() {
|
||||||
|
return Semver.inc(esTestConfig.getVersion(), 'minor') || '10.0.0';
|
||||||
|
}
|
||||||
|
|
||||||
|
function previousMinor() {
|
||||||
|
const [major, minor] = esTestConfig
|
||||||
|
.getVersion()
|
||||||
|
.split('.')
|
||||||
|
.map((s) => parseInt(s, 10));
|
||||||
|
// We should be fine for now. When we jump to the next major, we'll need to handle that.
|
||||||
|
return `${major}.${minor - 1}.0`;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Version Compatibility', () => {
|
||||||
|
let esServer: TestElasticsearchUtils | undefined;
|
||||||
|
let kibanaServer: TestKibanaUtils | undefined;
|
||||||
|
let abortController: AbortController | undefined;
|
||||||
|
let consoleSpy: jest.SpyInstance;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
consoleSpy = jest.spyOn(console, 'log');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
consoleSpy.mockRestore();
|
||||||
|
if (kibanaServer) {
|
||||||
|
await kibanaServer.stop();
|
||||||
|
} else {
|
||||||
|
abortController?.abort();
|
||||||
|
}
|
||||||
|
if (esServer) {
|
||||||
|
await esServer.stop();
|
||||||
|
}
|
||||||
|
kibanaServer = undefined;
|
||||||
|
abortController = undefined;
|
||||||
|
esServer = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const startServers = async ({
|
||||||
|
cliArgs,
|
||||||
|
customKibanaVersion,
|
||||||
|
ignoreVersionMismatch,
|
||||||
|
}: {
|
||||||
|
cliArgs?: Partial<CliArgs>;
|
||||||
|
customKibanaVersion?: string;
|
||||||
|
ignoreVersionMismatch?: boolean;
|
||||||
|
} = {}) => {
|
||||||
|
const { startES, startKibana } = createTestServers({
|
||||||
|
adjustTimeout: jest.setTimeout,
|
||||||
|
settings: {
|
||||||
|
kbn: {
|
||||||
|
cliArgs,
|
||||||
|
customKibanaVersion,
|
||||||
|
elasticsearch: {
|
||||||
|
ignoreVersionMismatch,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
esServer = await startES();
|
||||||
|
abortController = new AbortController();
|
||||||
|
kibanaServer = await startKibana(abortController.signal);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should start when versions match', async () => {
|
||||||
|
await expect(startServers({})).resolves.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should start when ES is next minor', async () => {
|
||||||
|
await expect(startServers({ customKibanaVersion: previousMinor() })).resolves.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should flag the incompatibility on version mismatch (ES is previous minor)', async () => {
|
||||||
|
const found$ = new Subject<void>();
|
||||||
|
consoleSpy.mockImplementation((str) => {
|
||||||
|
if (str.includes('is incompatible')) {
|
||||||
|
found$.next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await Promise.race([
|
||||||
|
firstValueFrom(found$),
|
||||||
|
startServers({ customKibanaVersion: nextMinor() }).then(() => {
|
||||||
|
throw new Error(
|
||||||
|
'Kibana completed the bootstrap without finding the incompatibility message'
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
new Promise((resolve, reject) =>
|
||||||
|
setTimeout(() => reject(new Error('Test timedout')), 5 * 60 * 1000)
|
||||||
|
),
|
||||||
|
]).finally(() => found$.complete());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore the version mismatch when option is set', async () => {
|
||||||
|
await expect(
|
||||||
|
startServers({
|
||||||
|
customKibanaVersion: nextMinor(),
|
||||||
|
cliArgs: { dev: true },
|
||||||
|
ignoreVersionMismatch: true,
|
||||||
|
})
|
||||||
|
).resolves.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow the option when not in dev mode', async () => {
|
||||||
|
await expect(
|
||||||
|
startServers({ customKibanaVersion: nextMinor(), ignoreVersionMismatch: true })
|
||||||
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`"[config validation of [elasticsearch].ignoreVersionMismatch]: \\"ignoreVersionMismatch\\" can only be set to true in development mode"`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore version mismatch when running on serverless mode and complete startup', async () => {
|
||||||
|
await expect(
|
||||||
|
startServers({ customKibanaVersion: nextMinor(), cliArgs: { serverless: true } })
|
||||||
|
).resolves.toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue