Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into kbn-37894-NP-agno…
Browse files Browse the repository at this point in the history
…stic-overlay-service
  • Loading branch information
pgayvallet committed Nov 19, 2019
2 parents 54916e9 + 2643f18 commit 0ae0157
Show file tree
Hide file tree
Showing 818 changed files with 8,075 additions and 3,601 deletions.
5 changes: 2 additions & 3 deletions .i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
"data": ["src/legacy/core_plugins/data", "src/plugins/data"],
"embeddableApi": "src/plugins/embeddable",
"esUi": "src/plugins/es_ui_shared",
"expressions_np": "src/plugins/expressions",
"expressions": "src/legacy/core_plugins/expressions",
"expressions": "src/plugins/expressions",
"inputControl": "src/legacy/core_plugins/input_control_vis",
"inspector": "src/plugins/inspector",
"inspectorViews": "src/legacy/core_plugins/inspector_views",
Expand All @@ -34,7 +33,7 @@
"visTypeTagCloud": "src/legacy/core_plugins/vis_type_tagcloud",
"visTypeTimeseries": "src/legacy/core_plugins/vis_type_timeseries",
"visTypeVega": "src/legacy/core_plugins/vis_type_vega",
"visualizations": "src/plugins/visualizations"
"visualizations": ["src/plugins/visualizations", "src/legacy/core_plugins/visualizations"]
},
"exclude": ["src/legacy/ui/ui_render/ui_render_mixin.js"],
"translations": []
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ Note that for VSCode, to enable "live" linting of TypeScript (and other) file ty
"eslint.autoFixOnSave": true,
```

It is **not** recommended to use `prettier` plugin on Kibana project. Because settings are in `eslintrc.js` file and it is applied to too many files that shouldn't be prettier-ized.
:warning: It is **not** recommended to use the [`Prettier` extension/IDE plugin](https://prettier.io/) while maintaining the Kibana project. Formatting and styling roles are set in the multiple `.eslintrc.js` files across the project and some of them use the [NPM version of Prettier](https://www.npmjs.com/package/prettier). Using the IDE extension might cause conflicts, applying the formatting to too many files that shouldn't be prettier-ized and/or highlighting errors that are actually OK.

### Internationalization

Expand Down
4 changes: 2 additions & 2 deletions docs/canvas/canvas-share-workpad.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ image::images/canvas-create-URL.gif[Create POST URL]
[[add-workpad-website]]
=== Share the workpad on a website

beta[] Download the workpad and share it on any website, then customize the workpad behavior to autoplay the pages or hide the toolbar.
beta[] Canvas allows you to create _shareables_, which are workpads that you download and securely share on any website. To customize the behavior of the workpad on your website, you can choose to autoplay the pages or hide the workpad toolbar.

. If you are using a Gold or Platinum license, enable reporting in your `config/kibana.yml` file.

Expand All @@ -74,7 +74,7 @@ NOTE: Shareable workpads encode the current state of the workpad in a JSON file.

[float]
[[change-the-workpad-settings]]
=== Change the shareable workpad settings
=== Change the settings

After you've added the workpad to your website, you can change the autoplay and toolbar settings.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Each route can have only one handler function, which is executed when the route

```ts
const router = createRouter();
// handler is called when '${my-plugin-id}/path' resource is requested with `GET` method
// handler is called when '/path' resource is requested with `GET` method
router.get({ path: '/path', validate: false }, (context, req, res) => res.ok({ content: 'ok' }));

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface HttpServiceSetup

## Example

To handle an incoming request in your plugin you should: - Create a `Router` instance. Router is already configured to use `plugin-id` to prefix path segment for your routes.
To handle an incoming request in your plugin you should: - Create a `Router` instance.

```ts
const router = httpSetup.createRouter();
Expand Down Expand Up @@ -61,7 +61,7 @@ const handler = async (context: RequestHandlerContext, request: KibanaRequest, r
}

```
- Register route handler for GET request to 'my-app/path/<!-- -->{<!-- -->id<!-- -->}<!-- -->' path
- Register route handler for GET request to 'path/<!-- -->{<!-- -->id<!-- -->}<!-- -->' path

```ts
import { schema, TypeOf } from '@kbn/config-schema';
Expand Down
2 changes: 1 addition & 1 deletion docs/management/managing-beats.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[role="xpack"]
== Managing {beats}

beta[]
include::{asciidoc-dir}/../../shared/discontinued.asciidoc[tag=cm-discontinued]

Use the Central Management UI under *Management > {beats}* to define and
manage configurations in a central location in {kib} and quickly deploy
Expand Down
9 changes: 6 additions & 3 deletions docs/maps/search.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ You can create a layer that requests data from {es} from the following:

** Grid aggregation source

** <<terms-join>>. The search context is applied to both the terms join and the vector source when the vector source is provided by Elasticsearch documents.
** <<terms-join>>

* <<heatmap-layer>> with Grid aggregation source

Expand Down Expand Up @@ -87,8 +87,11 @@ The most common cause for empty layers are searches for a field that exists in o
[[maps-disable-search-for-layer]]
==== Disable search for layer

To prevent the global search bar from applying search context to a layer, clear the *Apply global filter to layer* checkbox in Layer settings.
Disabling the search context applies to the layer source and all <<terms-join, term joins>> configured for the layer.
You can prevent the search bar from applying search context to a layer by configuring the following:

* In *Source settings*, clear the *Apply global filter to source* checkbox to turn off the global search context for the layer source.

* In *Term joins*, clear the *Apply global filter to join* checkbox to turn off the global search context for the <<terms-join, term join>>.

[float]
[[maps-add-index-search]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class Config {
this[$values] = value;
}

public has(key: string) {
public has(key: string | string[]) {
function recursiveHasCheck(
remainingPath: string[],
values: Record<string, any>,
Expand Down Expand Up @@ -109,7 +109,7 @@ export class Config {
return recursiveHasCheck(path, this[$values], schema);
}

public get(key: string, defaultValue?: any) {
public get(key: string | string[], defaultValue?: any) {
if (!this.has(key)) {
throw new Error(`Unknown config key "${key}"`);
}
Expand Down
85 changes: 77 additions & 8 deletions src/core/server/config/config_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ test('throws if config at path does not match schema', async () => {
await expect(
configService.setSchema('key', schema.string())
).rejects.toThrowErrorMatchingInlineSnapshot(
`"[key]: expected value of type [string] but got [number]"`
`"[config validation of [key]]: expected value of type [string] but got [number]"`
);
});

Expand All @@ -78,11 +78,11 @@ test('re-validate config when updated', async () => {
config$.next(new ObjectToConfigAdapter({ key: 123 }));

await expect(valuesReceived).toMatchInlineSnapshot(`
Array [
"value",
[Error: [key]: expected value of type [string] but got [number]],
]
`);
Array [
"value",
[Error: [config validation of [key]]: expected value of type [string] but got [number]],
]
`);
});

test("returns undefined if fetching optional config at a path that doesn't exist", async () => {
Expand Down Expand Up @@ -143,7 +143,7 @@ test("throws error if 'schema' is not defined for a key", async () => {
const configs = configService.atPath('key');

await expect(configs.pipe(first()).toPromise()).rejects.toMatchInlineSnapshot(
`[Error: No validation schema has been defined for key]`
`[Error: No validation schema has been defined for [key]]`
);
});

Expand All @@ -153,7 +153,7 @@ test("throws error if 'setSchema' called several times for the same key", async
const addSchema = async () => await configService.setSchema('key', schema.string());
await addSchema();
await expect(addSchema()).rejects.toMatchInlineSnapshot(
`[Error: Validation schema for key was already registered.]`
`[Error: Validation schema for [key] was already registered.]`
);
});

Expand Down Expand Up @@ -280,6 +280,33 @@ test('handles disabled path and marks config as used', async () => {
expect(unusedPaths).toEqual([]);
});

test('does not throw if schema does not define "enabled" schema', async () => {
const initialConfig = {
pid: {
file: '/some/file.pid',
},
};

const config$ = new BehaviorSubject(new ObjectToConfigAdapter(initialConfig));
const configService = new ConfigService(config$, defaultEnv, logger);
expect(
configService.setSchema(
'pid',
schema.object({
file: schema.string(),
})
)
).resolves.toBeUndefined();

const value$ = configService.atPath('pid');
const value: any = await value$.pipe(first()).toPromise();
expect(value.enabled).toBe(undefined);

const valueOptional$ = configService.optionalAtPath('pid');
const valueOptional: any = await valueOptional$.pipe(first()).toPromise();
expect(valueOptional.enabled).toBe(undefined);
});

test('treats config as enabled if config path is not present in config', async () => {
const initialConfig = {};

Expand All @@ -292,3 +319,45 @@ test('treats config as enabled if config path is not present in config', async (
const unusedPaths = await configService.getUnusedPaths();
expect(unusedPaths).toEqual([]);
});

test('read "enabled" even if its schema is not present', async () => {
const initialConfig = {
foo: {
enabled: true,
},
};

const config$ = new BehaviorSubject(new ObjectToConfigAdapter(initialConfig));
const configService = new ConfigService(config$, defaultEnv, logger);

const isEnabled = await configService.isEnabledAtPath('foo');
expect(isEnabled).toBe(true);
});

test('allows plugins to specify "enabled" flag via validation schema', async () => {
const initialConfig = {};

const config$ = new BehaviorSubject(new ObjectToConfigAdapter(initialConfig));
const configService = new ConfigService(config$, defaultEnv, logger);

await configService.setSchema(
'foo',
schema.object({ enabled: schema.boolean({ defaultValue: false }) })
);

expect(await configService.isEnabledAtPath('foo')).toBe(false);

await configService.setSchema(
'bar',
schema.object({ enabled: schema.boolean({ defaultValue: true }) })
);

expect(await configService.isEnabledAtPath('bar')).toBe(true);

await configService.setSchema(
'baz',
schema.object({ different: schema.boolean({ defaultValue: true }) })
);

expect(await configService.isEnabledAtPath('baz')).toBe(true);
});
26 changes: 20 additions & 6 deletions src/core/server/config/config_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class ConfigService {
public async setSchema(path: ConfigPath, schema: Type<unknown>) {
const namespace = pathToString(path);
if (this.schemas.has(namespace)) {
throw new Error(`Validation schema for ${path} was already registered.`);
throw new Error(`Validation schema for [${path}] was already registered.`);
}

this.schemas.set(namespace, schema);
Expand Down Expand Up @@ -98,14 +98,28 @@ export class ConfigService {
}

public async isEnabledAtPath(path: ConfigPath) {
const enabledPath = createPluginEnabledPath(path);
const namespace = pathToString(path);

const validatedConfig = this.schemas.has(namespace)
? await this.atPath<{ enabled?: boolean }>(path)
.pipe(first())
.toPromise()
: undefined;

const enabledPath = createPluginEnabledPath(path);
const config = await this.config$.pipe(first()).toPromise();
if (!config.has(enabledPath)) {

// if plugin hasn't got a config schema, we try to read "enabled" directly
const isEnabled =
validatedConfig && validatedConfig.enabled !== undefined
? validatedConfig.enabled
: config.get(enabledPath);

// not declared. consider that plugin is enabled by default
if (isEnabled === undefined) {
return true;
}

const isEnabled = config.get(enabledPath);
if (isEnabled === false) {
// If the plugin is _not_ enabled, we mark the entire plugin path as
// handled, as it's expected that it won't be used.
Expand Down Expand Up @@ -138,7 +152,7 @@ export class ConfigService {
const namespace = pathToString(path);
const schema = this.schemas.get(namespace);
if (!schema) {
throw new Error(`No validation schema has been defined for ${namespace}`);
throw new Error(`No validation schema has been defined for [${namespace}]`);
}
return schema.validate(
config,
Expand All @@ -147,7 +161,7 @@ export class ConfigService {
prod: this.env.mode.prod,
...this.env.packageInfo,
},
namespace
`config validation of [${namespace}]`
);
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions src/core/server/elasticsearch/elasticsearch_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,11 @@ test('#ssl.certificateAuthorities accepts both string and array of strings', ()
);
expect(configValue.ssl.certificateAuthorities).toEqual(['some-path', 'another-path']);
});

test('#username throws if equal to "elastic", only while running from source', () => {
const obj = {
username: 'elastic',
};
expect(() => config.schema.validate(obj, { dist: false })).toThrowErrorMatchingSnapshot();
expect(() => config.schema.validate(obj, { dist: true })).not.toThrow();
});
30 changes: 28 additions & 2 deletions src/core/server/elasticsearch/elasticsearch_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import { schema, TypeOf } from '@kbn/config-schema';
import { Duration } from 'moment';
import { Logger } from '../logging';

const hostURISchema = schema.uri({ scheme: ['http', 'https'] });

Expand All @@ -39,7 +40,23 @@ export const config = {
defaultValue: 'http://localhost:9200',
}),
preserveHost: schema.boolean({ defaultValue: true }),
username: schema.maybe(schema.string()),
username: schema.maybe(
schema.conditional(
schema.contextRef('dist'),
false,
schema.string({
validate: rawConfig => {
if (rawConfig === 'elastic') {
return (
'value of "elastic" is forbidden. This is a superuser account that can obfuscate ' +
'privilege-related issues. You should use the "kibana" user instead.'
);
}
},
}),
schema.string()
)
),
password: schema.maybe(schema.string()),
requestHeadersWhitelist: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], {
defaultValue: ['authorization'],
Expand Down Expand Up @@ -166,7 +183,7 @@ export class ElasticsearchConfig {
*/
public readonly customHeaders: ElasticsearchConfigType['customHeaders'];

constructor(rawConfig: ElasticsearchConfigType) {
constructor(rawConfig: ElasticsearchConfigType, log?: Logger) {
this.ignoreVersionMismatch = rawConfig.ignoreVersionMismatch;
this.apiVersion = rawConfig.apiVersion;
this.logQueries = rawConfig.logQueries;
Expand Down Expand Up @@ -195,5 +212,14 @@ export class ElasticsearchConfig {
...rawConfig.ssl,
certificateAuthorities,
};

if (this.username === 'elastic' && log !== undefined) {
// logger is optional / not used during tests
// TODO: logger can be removed when issue #40255 is resolved to support deprecations in NP config service
log.warn(
`Setting the elasticsearch username to "elastic" is deprecated. You should use the "kibana" user instead.`,
{ tags: ['deprecation'] }
);
}
}
}
2 changes: 1 addition & 1 deletion src/core/server/elasticsearch/elasticsearch_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class ElasticsearchService implements CoreService<InternalElasticsearchSe
this.log = coreContext.logger.get('elasticsearch-service');
this.config$ = coreContext.configService
.atPath<ElasticsearchConfigType>('elasticsearch')
.pipe(map(rawConfig => new ElasticsearchConfig(rawConfig)));
.pipe(map(rawConfig => new ElasticsearchConfig(rawConfig, coreContext.logger.get('config'))));
}

public async setup(deps: SetupDeps): Promise<InternalElasticsearchServiceSetup> {
Expand Down
Loading

0 comments on commit 0ae0157

Please sign in to comment.