Skip to content

Commit

Permalink
Merge branch 'master' into monitoring/cloud_test_failures
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine authored Aug 26, 2020
2 parents 6cdd729 + eee1392 commit e011eff
Show file tree
Hide file tree
Showing 42 changed files with 507 additions and 274 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,4 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
| [savedObjects](./kibana-plugin-core-server.coresetup.savedobjects.md) | <code>SavedObjectsServiceSetup</code> | [SavedObjectsServiceSetup](./kibana-plugin-core-server.savedobjectsservicesetup.md) |
| [status](./kibana-plugin-core-server.coresetup.status.md) | <code>StatusServiceSetup</code> | [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md) |
| [uiSettings](./kibana-plugin-core-server.coresetup.uisettings.md) | <code>UiSettingsServiceSetup</code> | [UiSettingsServiceSetup](./kibana-plugin-core-server.uisettingsservicesetup.md) |
| [uuid](./kibana-plugin-core-server.coresetup.uuid.md) | <code>UuidServiceSetup</code> | [UuidServiceSetup](./kibana-plugin-core-server.uuidservicesetup.md) |

This file was deleted.

1 change: 0 additions & 1 deletion docs/development/core/server/kibana-plugin-core-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [UiSettingsServiceStart](./kibana-plugin-core-server.uisettingsservicestart.md) | |
| [URLMeaningfulParts](./kibana-plugin-core-server.urlmeaningfulparts.md) | We define our own typings because the current version of @<!-- -->types/node declares properties to be optional "hostname?: string". Although, parse call returns "hostname: null \| string". |
| [UserProvidedValues](./kibana-plugin-core-server.userprovidedvalues.md) | Describes the values explicitly set by user. |
| [UuidServiceSetup](./kibana-plugin-core-server.uuidservicesetup.md) | APIs to access the application's instance uuid. |

## Variables

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
env: {
mode: EnvironmentMode;
packageInfo: Readonly<PackageInfo>;
instanceUuid: string;
};
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface PluginInitializerContext<ConfigSchema = unknown>
| Property | Type | Description |
| --- | --- | --- |
| [config](./kibana-plugin-core-server.plugininitializercontext.config.md) | <code>{</code><br/><code> legacy: {</code><br/><code> globalConfig$: Observable&lt;SharedGlobalConfig&gt;;</code><br/><code> };</code><br/><code> create: &lt;T = ConfigSchema&gt;() =&gt; Observable&lt;T&gt;;</code><br/><code> createIfExists: &lt;T = ConfigSchema&gt;() =&gt; Observable&lt;T &#124; undefined&gt;;</code><br/><code> }</code> | |
| [env](./kibana-plugin-core-server.plugininitializercontext.env.md) | <code>{</code><br/><code> mode: EnvironmentMode;</code><br/><code> packageInfo: Readonly&lt;PackageInfo&gt;;</code><br/><code> }</code> | |
| [env](./kibana-plugin-core-server.plugininitializercontext.env.md) | <code>{</code><br/><code> mode: EnvironmentMode;</code><br/><code> packageInfo: Readonly&lt;PackageInfo&gt;;</code><br/><code> instanceUuid: string;</code><br/><code> }</code> | |
| [logger](./kibana-plugin-core-server.plugininitializercontext.logger.md) | <code>LoggerFactory</code> | |
| [opaqueId](./kibana-plugin-core-server.plugininitializercontext.opaqueid.md) | <code>PluginOpaqueId</code> | |

This file was deleted.

This file was deleted.

79 changes: 79 additions & 0 deletions src/core/server/environment/create_data_folder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { PathConfigType } from '../path';
import { createDataFolder } from './create_data_folder';
import { mkdir } from './fs';
import { loggingSystemMock } from '../logging/logging_system.mock';

jest.mock('./fs', () => ({
mkdir: jest.fn(() => Promise.resolve('')),
}));

const mkdirMock = mkdir as jest.Mock;

describe('createDataFolder', () => {
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
let pathConfig: PathConfigType;

beforeEach(() => {
logger = loggingSystemMock.createLogger();
pathConfig = {
data: '/path/to/data/folder',
};
mkdirMock.mockResolvedValue(undefined);
});

afterEach(() => {
jest.clearAllMocks();
});

it('calls `mkdir` with the correct parameters', async () => {
await createDataFolder({ pathConfig, logger });
expect(mkdirMock).toHaveBeenCalledTimes(1);
expect(mkdirMock).toHaveBeenCalledWith(pathConfig.data, { recursive: true });
});

it('does not log error if the `mkdir` call is successful', async () => {
await createDataFolder({ pathConfig, logger });
expect(logger.error).not.toHaveBeenCalled();
});

it('throws an error if the `mkdir` call fails', async () => {
mkdirMock.mockRejectedValue('some-error');
await expect(() => createDataFolder({ pathConfig, logger })).rejects.toMatchInlineSnapshot(
`"some-error"`
);
});

it('logs an error message if the `mkdir` call fails', async () => {
mkdirMock.mockRejectedValue('some-error');
try {
await createDataFolder({ pathConfig, logger });
} catch (e) {
/* trap */
}
expect(logger.error).toHaveBeenCalledTimes(1);
expect(logger.error.mock.calls[0]).toMatchInlineSnapshot(`
Array [
"Error trying to create data folder at /path/to/data/folder: some-error",
]
`);
});
});
40 changes: 40 additions & 0 deletions src/core/server/environment/create_data_folder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { mkdir } from './fs';
import { Logger } from '../logging';
import { PathConfigType } from '../path';

export async function createDataFolder({
pathConfig,
logger,
}: {
pathConfig: PathConfigType;
logger: Logger;
}): Promise<void> {
const dataFolder = pathConfig.data;
try {
// Create the data directory (recursively, if the a parent dir doesn't exist).
// If it already exists, does nothing.
await mkdir(dataFolder, { recursive: true });
} catch (e) {
logger.error(`Error trying to create data folder at ${dataFolder}: ${e}`);
throw e;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,25 @@
* under the License.
*/

import { UuidService, UuidServiceSetup } from './uuid_service';
import { EnvironmentService, InternalEnvironmentServiceSetup } from './environment_service';

const createSetupContractMock = () => {
const setupContract: jest.Mocked<UuidServiceSetup> = {
getInstanceUuid: jest.fn().mockImplementation(() => 'uuid'),
const setupContract: jest.Mocked<InternalEnvironmentServiceSetup> = {
instanceUuid: 'uuid',
};
return setupContract;
};

type UuidServiceContract = PublicMethodsOf<UuidService>;
type EnvironmentServiceContract = PublicMethodsOf<EnvironmentService>;
const createMock = () => {
const mocked: jest.Mocked<UuidServiceContract> = {
const mocked: jest.Mocked<EnvironmentServiceContract> = {
setup: jest.fn(),
};
mocked.setup.mockResolvedValue(createSetupContractMock());
return mocked;
};

export const uuidServiceMock = {
export const environmentServiceMock = {
create: createMock,
createSetupContract: createSetupContractMock,
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,83 @@
* under the License.
*/

import { UuidService } from './uuid_service';
import { BehaviorSubject } from 'rxjs';
import { EnvironmentService } from './environment_service';
import { resolveInstanceUuid } from './resolve_uuid';
import { createDataFolder } from './create_data_folder';
import { CoreContext } from '../core_context';

import { configServiceMock } from '../config/config_service.mock';
import { loggingSystemMock } from '../logging/logging_system.mock';
import { mockCoreContext } from '../core_context.mock';

jest.mock('./resolve_uuid', () => ({
resolveInstanceUuid: jest.fn().mockResolvedValue('SOME_UUID'),
}));

jest.mock('./create_data_folder', () => ({
createDataFolder: jest.fn(),
}));

const pathConfig = {
data: 'data-folder',
};
const serverConfig = {
uuid: 'SOME_UUID',
};

const getConfigService = () => {
const configService = configServiceMock.create();
configService.atPath.mockImplementation((path) => {
if (path === 'path') {
return new BehaviorSubject(pathConfig);
}
if (path === 'server') {
return new BehaviorSubject(serverConfig);
}
return new BehaviorSubject({});
});
return configService;
};

describe('UuidService', () => {
let logger: ReturnType<typeof loggingSystemMock.create>;
let configService: ReturnType<typeof configServiceMock.create>;
let coreContext: CoreContext;

beforeEach(() => {
jest.clearAllMocks();
logger = loggingSystemMock.create();
coreContext = mockCoreContext.create({ logger });
configService = getConfigService();
coreContext = mockCoreContext.create({ logger, configService });
});

describe('#setup()', () => {
it('calls resolveInstanceUuid with core configuration service', async () => {
const service = new UuidService(coreContext);
it('calls resolveInstanceUuid with correct parameters', async () => {
const service = new EnvironmentService(coreContext);
await service.setup();
expect(resolveInstanceUuid).toHaveBeenCalledTimes(1);
expect(resolveInstanceUuid).toHaveBeenCalledWith({
configService: coreContext.configService,
pathConfig,
serverConfig,
logger: logger.get('uuid'),
});
});

it('calls createDataFolder with correct parameters', async () => {
const service = new EnvironmentService(coreContext);
await service.setup();
expect(createDataFolder).toHaveBeenCalledTimes(1);
expect(createDataFolder).toHaveBeenCalledWith({
pathConfig,
logger: logger.get('uuid'),
});
});

it('returns the uuid resolved from resolveInstanceUuid', async () => {
const service = new UuidService(coreContext);
const service = new EnvironmentService(coreContext);
const setup = await service.setup();
expect(setup.getInstanceUuid()).toEqual('SOME_UUID');
expect(setup.instanceUuid).toEqual('SOME_UUID');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,27 @@
* under the License.
*/

import { resolveInstanceUuid } from './resolve_uuid';
import { take } from 'rxjs/operators';
import { CoreContext } from '../core_context';
import { Logger } from '../logging';
import { IConfigService } from '../config';
import { PathConfigType, config as pathConfigDef } from '../path';
import { HttpConfigType, config as httpConfigDef } from '../http';
import { resolveInstanceUuid } from './resolve_uuid';
import { createDataFolder } from './create_data_folder';

/**
* APIs to access the application's instance uuid.
*
* @public
* @internal
*/
export interface UuidServiceSetup {
export interface InternalEnvironmentServiceSetup {
/**
* Retrieve the Kibana instance uuid.
*/
getInstanceUuid(): string;
instanceUuid: string;
}

/** @internal */
export class UuidService {
export class EnvironmentService {
private readonly log: Logger;
private readonly configService: IConfigService;
private uuid: string = '';
Expand All @@ -46,13 +48,21 @@ export class UuidService {
}

public async setup() {
const [pathConfig, serverConfig] = await Promise.all([
this.configService.atPath<PathConfigType>(pathConfigDef.path).pipe(take(1)).toPromise(),
this.configService.atPath<HttpConfigType>(httpConfigDef.path).pipe(take(1)).toPromise(),
]);

await createDataFolder({ pathConfig, logger: this.log });

this.uuid = await resolveInstanceUuid({
configService: this.configService,
pathConfig,
serverConfig,
logger: this.log,
});

return {
getInstanceUuid: () => this.uuid,
instanceUuid: this.uuid,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ import { promisify } from 'util';

export const readFile = promisify(Fs.readFile);
export const writeFile = promisify(Fs.writeFile);
export const mkdir = promisify(Fs.mkdir);
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
* under the License.
*/

export { UuidService, UuidServiceSetup } from './uuid_service';
export { EnvironmentService, InternalEnvironmentServiceSetup } from './environment_service';
Loading

0 comments on commit e011eff

Please sign in to comment.