Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate instance uuid logic to new platform #52060

Merged
merged 27 commits into from
Dec 17, 2019

Conversation

pgayvallet
Copy link
Contributor

@pgayvallet pgayvallet commented Dec 3, 2019

Summary

Fix #48956

Migrate the code that was managing the instance uuid and writing it to file (formerly in src/legacy/core_plugins/kibana/server/lib/manage_uuid.js) to new platform.

As the only public API exposed from this feature is a constant-like, I tried to expose it to plugins via the PluginInitializerContext (something like pluginInitializerContext.instanceUuid). However the plugins PluginInitializerContext is created during plugin discovery, which is done before configuration validation. As we decided in #49378 that no config access should be performed before config validation, and as the uuid logic relies on reading the config, I had to fallback to a more classic service approach (core.uuid)

Checklist

Use strikethroughs to remove checklist items you don't feel are applicable to this PR.

- [ ] This was checked for cross-browser compatibility, including a check against IE11
- [ ] Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support

For maintainers

- [ ] This was checked for breaking API changes and was labeled appropriately
- [ ] This includes a feature addition or change that requires a release note and was labeled appropriately

@elasticmachine
Copy link
Contributor

💔 Build Failed

@pgayvallet
Copy link
Contributor Author

Waiting for #51478 to be merged (need path.data access in NP config)

@elasticmachine

This comment has been minimized.

Comment on lines -48 to +49
export type KibanaConfig = LegacyConfig;
// lot of legacy code was assuming this type only had these two methods
export type KibanaConfig = Pick<LegacyConfig, 'get' | 'has'>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added set method in LegacyConfig to set the uuid in it for legacy compatibility. However a LOT of code in legacy made the assumption that KibanaConfig only had get and has.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised having set would break anything?

Copy link
Contributor Author

@pgayvallet pgayvallet Dec 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of TS errors, mostly (but not only) in test code, similars to:

Type '() => { get<T>(key: string): any; has(key: string): boolean; }' is not assignable to type '() => LegacyConfig'.
        Property 'set' is missing in type '{ get<T>(key: string): any; has(key: string): boolean; }' but required in type 'LegacyConfig'

As set isn't used in legacy anyway, It felt like is was more pragmatic to restrict the type than to adapt something like 25 usages in multiple solutions code.

@@ -91,6 +91,7 @@ export const config = {
)
),
}),
uuid: schema.maybe(schema.string()),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like having to add this here, as the server config namespace is now more like only the http config, However the current property is server.uuid, so I don't really see another way.

We could deprecates/rename that once the config deprecation PR lands if we want to.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a note to the config refactoring issue just so we don't forget?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the legacy config, we validated this as a valid guid. Can we add that validation here as well? Should be able to specify a custom validate option to schema.string()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good catch, totally forgot about that

Comment on lines 55 to 56
// propagate the instance uuid to the legacy config, as it was the legacy way to access it.
legacyPlugins.pluginExtendedConfig.set('server.uuid', this.uuid);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The legacy way to access the instance uuid was via the config... the legacy mixin was writing it during server init.

I tried to migrates the legacy usages of config.get('server.uuid'), however some calls are very deeply nested in places where the server, and therefor the NP API, is not accessible. So to preserve retro-compatibility, I was kinda forced to do that.

Tell me if we think this is not acceptable and if I should migrate all calls instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to move this code into the LegacyService instead? That way we can more easily delete legacy code without having to modify this as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. The legacy service tests mocks requirements are growing though. It was harder than expected to move the legacy config set test here.


public async setup({ legacyPlugins }: SetupDeps) {
this.uuid = await manageInstanceUuid(this.configService);
this.log.info(`Kibana instance UUID: ${this.uuid}`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The legacy was logging different (but very similar) messages depending on where the uuid was read from. I think we don't really care, and that the only important info is the actual UUID, so I simplified. Please tell me if I'm wrong.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we necessarily care, but seeing how this does affect startup and some critical functions (task_manager) maybe it would be good to retain some insight. That said, I think downgrading the detailed messages to debug would be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, adapted to use the exact same messages we had in legacy, and used debug instead of info

@pgayvallet pgayvallet added v7.6.0 v8.0.0 release_note:skip Skip the PR/issue when compiling release notes Feature:New Platform labels Dec 6, 2019
@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@pgayvallet pgayvallet added the Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc label Dec 6, 2019
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-platform (Team:Platform)

@pgayvallet pgayvallet marked this pull request as ready for review December 6, 2019 17:13
@pgayvallet pgayvallet requested a review from a team as a code owner December 6, 2019 17:13
Comment on lines 55 to 56
// propagate the instance uuid to the legacy config, as it was the legacy way to access it.
legacyPlugins.pluginExtendedConfig.set('server.uuid', this.uuid);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to move this code into the LegacyService instead? That way we can more easily delete legacy code without having to modify this as well.

Comment on lines 37 to 45
configService
.atPath<PathConfigType>('path')
.pipe(take(1))
.toPromise(),
configService
.atPath<HttpConfigType>('server')
.pipe(take(1))
.toPromise(),
]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use config.path from the original modules rather than hardcoded strings.


const uuidFilePath = join(pathConfig.data, FILE_NAME);

const uuidFromFile = await readUUIDFromFile(uuidFilePath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super nit: can we capitalize all these UUID names with the same convention used elsewhere: readUuidFromFile

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I'm more of a UUID person myself, so I had to rename all theses after asking about our conventions. Missed some, will fix that.

const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);

export async function manageInstanceUuid(configService: IConfigService): Promise<string> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export async function manageInstanceUuid(configService: IConfigService): Promise<string> {
export async function resolveInstanceUuid(configService: IConfigService): Promise<string> {

seems more descriptive than manage?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better. Wasn't that inspired with the name. Changed.

Comment on lines -48 to +49
export type KibanaConfig = LegacyConfig;
// lot of legacy code was assuming this type only had these two methods
export type KibanaConfig = Pick<LegacyConfig, 'get' | 'has'>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised having set would break anything?


public async setup({ legacyPlugins }: SetupDeps) {
this.uuid = await manageInstanceUuid(this.configService);
this.log.info(`Kibana instance UUID: ${this.uuid}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we necessarily care, but seeing how this does affect startup and some critical functions (task_manager) maybe it would be good to retain some insight. That said, I think downgrading the detailed messages to debug would be fine.

@@ -91,6 +91,7 @@ export const config = {
)
),
}),
uuid: schema.maybe(schema.string()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a note to the config refactoring issue just so we don't forget?

src/core/server/uuid/uuid_service.ts Show resolved Hide resolved
src/core/server/uuid/resolve_uuid.ts Outdated Show resolved Hide resolved
// non-existent uuid file is ok, we will create it.
return undefined;
}
throw e;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible that we get a EACCESS error here and in writeUuidToFile we might also get EISDIR. I think it would be worth catching these errors and throwing a more useful error to users, maybe something like:

Unable to write Kibana UUID file, please check the uuid.server configuration value in kibana.yml and ensure Kibana has sufficient permissions to read / write to this file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would also be worth testing these error conditions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicit error message is indeed better.

await expect(
resolveInstanceUuid(configService, logger)
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Unable to write Kibana UUID file, please check the uuid.server configurationvalue in kibana.yml and ensure Kibana has sufficient permissions to read / write to this file. Error was: undefined"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Error was: undefined" doesn't seem right.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn. thanks you. That's the actual main reason why I hate snapshot testing. That makes developer lazy and leads to that kind of errors.

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@pgayvallet pgayvallet merged commit 2426811 into elastic:master Dec 17, 2019
pgayvallet added a commit to pgayvallet/kibana that referenced this pull request Dec 17, 2019
* move and migrate uuid code to new platform

* create and wire uuid service

* handle legacy compatibility

* update generated docs

* add `set` to LegacyConfig interface

* Fix types

* fix config access

* respect naming conventions for uuid

* remove hardcoded config paths

* rename manageInstanceUuid to resolveInstanceUuid

* moves legacy config uuid set from uuid to legacy service

* log specific message depending on how uuid was resolved

* resolve merge conflicts

* use fs.promises

* add forgotten @public in uuid contract

* add explicit errors and tests

* ensure uuid is valid in configuration

* fix read/write tests
pgayvallet added a commit that referenced this pull request Dec 17, 2019
* move and migrate uuid code to new platform

* create and wire uuid service

* handle legacy compatibility

* update generated docs

* add `set` to LegacyConfig interface

* Fix types

* fix config access

* respect naming conventions for uuid

* remove hardcoded config paths

* rename manageInstanceUuid to resolveInstanceUuid

* moves legacy config uuid set from uuid to legacy service

* log specific message depending on how uuid was resolved

* resolve merge conflicts

* use fs.promises

* add forgotten @public in uuid contract

* add explicit errors and tests

* ensure uuid is valid in configuration

* fix read/write tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:New Platform release_note:skip Skip the PR/issue when compiling release notes Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v7.6.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Migrate UUID logic to NP Core
5 participants