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

Serve.js refactors #158750

Merged
merged 13 commits into from Jun 8, 2023
Merged

Serve.js refactors #158750

merged 13 commits into from Jun 8, 2023

Conversation

delanni
Copy link
Contributor

@delanni delanni commented May 31, 2023

Summary

Closes #155137, with some extra reorganisation, modularisation and unit tests.

Refactors to maybeAddConfig

Mostly in (b8fa2a0)

Refactoring serve.js <-> bootstrap.ts

Previously, both of these files were involved with assessing wether a use-case is a serverless case or not. serve.js would assess if the runtime options point to a serverless run. If so, it would write a flag to a config file, and add it to the config stack. bootstrap.ts would read the config stack, assess if ultimately it's a case of serverless run (either through the options and the written file, or through any other config file containing the serverless setting), then optionally extend the config stack, and reload the configs. It seemed that the concern of figuring out what's the final configuration stack was split across two files, and that's why 'hacks' were needed.

My attempt was to compartmentalise the code for figuring out what's the final configuration stack (the list of configs that would be merged) within serve.js, so that:

  • serve.js alone can decide on the final stack of configs
  • bootstrap.ts can be agnostic of the config stack, just receive it, and use it
  • this also allows for modularising the compiling of the config set and order, and allowing for unit tests

Unit tests for compileConfigStack

This replaces integration tests around serve.js and bootstrap.ts that examine config lists w/r/t serverless.

Checklist

@delanni delanni requested a review from a team as a code owner May 31, 2023 16:36
Copy link
Member

@afharo afharo left a comment

Choose a reason for hiding this comment

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

I love that we are simplifying (or, at least, bringing together the handling of the config files), and I'd love to have this merged.

However, I think that we are breaking the current Project Switcher's functionality. Refer to this comment for the expected flow.

configs.unshift(resolveConfig(`serverless.${serverlessMode}.yml`));
configs.unshift(resolveConfig('serverless.yml'));

if (opts.dev) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: I wonder if we should check opts.devConfig !== false here 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.

It's a fair question. I don't know how it should work, or what the use of the --no-dev-config flag could be in practise. I'm happy to extend this condition, and include it in the help-text too.

Copy link
Member

Choose a reason for hiding this comment

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

IMO, we should remove serverless.dev.yml (I don't fully get what's its purpose), but that's unrelated to this PR.

If we did that, I think it's fine the way it is right now (no need for the ops.devConfig check.

Comment on lines -55 to -79
// Hack to load the extra serverless config files if `serverless: {projectType}` is found in it.
const rawConfig = await firstValueFrom(rawConfigService.getConfig$());
const serverlessProjectType = rawConfig?.serverless;
if (
typeof serverlessProjectType === 'string' &&
VALID_SERVERLESS_PROJECT_TYPES.includes(serverlessProjectType)
) {
const extendedConfigs = [
...['serverless.yml', `serverless.${serverlessProjectType}.yml`]
.map((name) => resolve(getConfigDirectory(), name))
.filter(configFileExists),
...configs,
];

env = Env.createDefault(REPO_ROOT, {
configs: extendedConfigs,
cliArgs: { ...cliArgs, serverless: true },
repoPackages: getPackages(REPO_ROOT),
});

rawConfigService.stop();
rawConfigService = new RawConfigService(env.configs, applyConfigOverrides);
rawConfigService.loadConfig();
}

Copy link
Member

Choose a reason for hiding this comment

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

Thank you for moving this back to the serve.js file 🧡

if (opts.dev) {
configs.push(resolveConfig('serverless.dev.yml'));

writeProjectSwitcherConfig('serverless.recent.dev.yml');
Copy link
Member

Choose a reason for hiding this comment

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

I love that we renamed serverless.recent.yml to serverless.recent.dev.yml. It makes it more obvious that this file won't exist in production, and that it's a dev utility.

Just remember to change it here as well. A potential solution could be to add the path to the file in the config so the route always knows where it lives.

src/cli/serve/serve.js Outdated Show resolved Hide resolved
configs.push(resolveConfig('serverless.dev.yml'));

writeProjectSwitcherConfig('serverless.recent.dev.yml');
configs.push(resolveConfig('serverless.recent.dev.yml'));
Copy link
Member

Choose a reason for hiding this comment

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

IMO, we should only add this file if --serverless is true. With the changes proposed in this PR, for explicit project types, it shouldn't be used.

// Filtering out all config paths that didn't exist
configs = configs.filter(Boolean);

const serverlessMode = getServerlessModeFromOpts(opts) || getServerlessModeFromCfg(configs);
Copy link
Member

Choose a reason for hiding this comment

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

IMO, this check needs to be more complex:

If we keep it like this, it'll break the project switcher's dev functionality. Typical flow:

  1. Dev starts Kibana with yarn start --serverless (no project specified)
  2. The first time, Project Switcher defaults to es ✅. Otherwise, it checks the latest project type it was running (it was stored in serverless.recent.yml) 🛑 with this approach, opts.serverless === true will always return es.
  3. While running Kibana, the developer could switch the project type. POST /internal/serverless/switch_project would write the selected project type in serverless.recent.yml, and the watcher would trigger a Kibana restart. serve.js reads this new config and starts Kibana in the new project type.

Of course, this logic applies only if the CLI option --serverless is true (no explicit project selected).

cc @clintandrewhall as the original author of Project Switcher in case I missed any feature 😇

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Understood! This was an oversight from my side, I automatically placed the concepts together (serverless => project switcher). I'll iron this out in a minute!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@afharo - according to the original logic, the most recent --serverless choice is also persisted in the file anytime it's a string. I'll adjust my code to reflect this behaviour

@delanni delanni mentioned this pull request Jun 2, 2023
1 task
@delanni delanni added backport:skip This commit does not require backporting release_note:skip Skip the PR/issue when compiling release notes labels Jun 2, 2023
@delanni delanni marked this pull request as draft June 2, 2023 09:20
@delanni delanni added the Team:Operations Team label for Operations Team label Jun 2, 2023
@delanni delanni mentioned this pull request Jun 2, 2023
1 task
@delanni delanni changed the title Further serve refactors Serve.js refactors Jun 2, 2023
@delanni
Copy link
Contributor Author

delanni commented Jun 5, 2023

@elasticmachine merge upstream

@delanni delanni marked this pull request as ready for review June 5, 2023 09:34
@delanni delanni requested a review from a team as a code owner June 5, 2023 09:34
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-operations (Team:Operations)

@delanni
Copy link
Contributor Author

delanni commented Jun 6, 2023

@afharo / @elastic/kibana-core - this is now ready for review, I think.

One more thing I could easily add: should I rewrite the new component to typescript? It's always hard to tell whether I should change code to Typescript next to other sources written in Javascript, but this one would be a nobrainer.

Copy link
Member

@afharo afharo left a comment

Choose a reason for hiding this comment

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

I haven't tested it. But code changes LGTM.

const root = new Root(rawConfigService, env, onRootShutdown);
const cliLogger = root.logger.get('cli');

cliLogger.debug('Kibana configurations evaluated in this order: ' + env.configs.join(', '));
Copy link
Member

Choose a reason for hiding this comment

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

Q: should we keep this?

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 could add it back, at a debug level, it's probably useful

Copy link
Member

Choose a reason for hiding this comment

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

Yes, please! I'm sure it'll save us from some headaches in the future :)

configs.push(resolveConfig('kibana.dev.yml'));
}

if (dev && serverless) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: we only need the recent file when the serverless flag didn't specify a project

Suggested change
if (dev && serverless) {
if (dev && serverless === true) {

I'm aware that's not the current behaviour. Happy if we change it in a follow-up PR.

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'll probably not want to change behaviour in this PR, to keep it as a refactor, and not to have to explain myself if anyone asks me :-)

Copy link
Member

Choose a reason for hiding this comment

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

++ no need to change it in this PR. Let's keep the scope of this PR to a refactor :)

Comment on lines +52 to +55
if (dev && devConfig !== false) {
configs.push(resolveConfig('serverless.dev.yml'));
configs.push(resolveConfig(`serverless.${serverlessMode}.dev.yml`));
}
Copy link
Member

Choose a reason for hiding this comment

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

TBH, I don't see the value of these files...

serverless.yml and serverless.${serverlessMode}.yml files are supposed to set the defaults for the Serverless offering. Having .dev files that override them for dev feels like something's wrong about our defaults (especially, since we already have kibana.dev.yml for things like pointing a service to a local service.

However, I wouldn't consider this a blocker for this PR.

cc @lukeelmers, WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

Spencer's original PR had support for these project-specific .dev.yml files which I think got lost in a later update:

kibana/config/README.md

Lines 7 to 16 in f48b742

configuration is applied in the following order, later values override
1. serverless.yml (serverless configs go first)
2. serverless.{mode}.yml (serverless configs go first)
3. base config, in this preference order:
- my-config.yml(s) (set by --config)
- env-config.yml (described by `env.KBN_CONFIG_PATHS`)
- kibana.yml (default @ `env.KBN_PATH_CONF`/kibana.yml)
4. kibana.dev.yml
5. serverless.dev.yml
6. serverless.{mode}.dev.yml

I don't have a strong feeling on this. Since kibana.dev.yml always wins, I don't think there's a functional need for the project-specific dev overrides. It's just more of an organizational question... If folks want to override a security-specific setting, for example, it may be clearer to have the ability to copy that into a designated file that they could easily map back to the original security serverless yml.

It's a dev-only feature, so if there's anyone who would find it useful and it doesn't cost us much to maintain, then I don't see any harm in keeping it.

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'm easily swayed towards either behaviour, let me know which one you prefer (keep the specific configs, or only have kibana.dev.yml)

Copy link
Member

Choose a reason for hiding this comment

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

It's a dev-only feature, so if there's anyone who would find it useful and it doesn't cost us much to maintain, then I don't see any harm in keeping it.

My main concern is that a dev perceives a different behaviour just because they are using those serverless.*dev.yml files and forgot about them.

Having said that, I don't think we need to increase the scope of this PR. We can discuss it, and remove those later if needed.

Comment on lines +144 to +147
if (serverlessMode === true) {
// Defaulting to read the project-switcher's settings in `serverless.recent.dev.yml`
return null;
}
Copy link
Member

Choose a reason for hiding this comment

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

🧡

@@ -63,7 +63,7 @@ export class ServerlessPlugin implements Plugin<ServerlessPluginSetup, Serverles
// with a specific config. So in this case, to ensure the switcher remains enabled,
// write the selected config to `recent` and tack on the setting to enable the switcher.
writeFileSync(
resolve(getConfigDirectory(), 'serverless.recent.yml'),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@elastic/appex-sharedux - could you check if you're okay with this small change. We changed the name of the generated config file to serverless.recent.dev.yml

@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Unknown metric groups

ESLint disabled line counts

id before after diff
enterpriseSearch 19 21 +2
securitySolution 414 418 +4
total +6

Total ESLint disabled count

id before after diff
enterpriseSearch 20 22 +2
securitySolution 498 502 +4
total +6

History

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

Copy link
Member

@tsullivan tsullivan left a comment

Choose a reason for hiding this comment

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

serverless plugin changes LGTM

@delanni delanni merged commit f51f5f4 into elastic:main Jun 8, 2023
16 checks passed
jbudz added a commit that referenced this pull request Jun 13, 2023
Prior to #158750, `bin/kibana
--serverless=<project>` was able to load project specific configurations
on Kibana distributions.

This was used in functional tests
[here](https://github.com/elastic/kibana/blob/main/x-pack/test_serverless/functional/config.base.ts#L31),
but admittedly may not be the correct way to start the Kibana server.

Opening this up for discussion

1) Do we want to support `bin/kibana --serverless`?
2) What's the recommended way to run a distribution in serverless mode?

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
saarikabhasi pushed a commit to saarikabhasi/kibana that referenced this pull request Jun 13, 2023
Prior to elastic#158750, `bin/kibana
--serverless=<project>` was able to load project specific configurations
on Kibana distributions.

This was used in functional tests
[here](https://github.com/elastic/kibana/blob/main/x-pack/test_serverless/functional/config.base.ts#L31),
but admittedly may not be the correct way to start the Kibana server.

Opening this up for discussion

1) Do we want to support `bin/kibana --serverless`?
2) What's the recommended way to run a distribution in serverless mode?

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
saarikabhasi pushed a commit to saarikabhasi/kibana that referenced this pull request Jun 13, 2023
Prior to elastic#158750, `bin/kibana
--serverless=<project>` was able to load project specific configurations
on Kibana distributions.

This was used in functional tests
[here](https://github.com/elastic/kibana/blob/main/x-pack/test_serverless/functional/config.base.ts#L31),
but admittedly may not be the correct way to start the Kibana server.

Opening this up for discussion

1) Do we want to support `bin/kibana --serverless`?
2) What's the recommended way to run a distribution in serverless mode?

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
saarikabhasi pushed a commit to saarikabhasi/kibana that referenced this pull request Jun 14, 2023
Prior to elastic#158750, `bin/kibana
--serverless=<project>` was able to load project specific configurations
on Kibana distributions.

This was used in functional tests
[here](https://github.com/elastic/kibana/blob/main/x-pack/test_serverless/functional/config.base.ts#L31),
but admittedly may not be the correct way to start the Kibana server.

Opening this up for discussion

1) Do we want to support `bin/kibana --serverless`?
2) What's the recommended way to run a distribution in serverless mode?

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
@delanni delanni deleted the further-serve-refactors branch May 2, 2024 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:Operations Team label for Operations Team v8.9.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Simplify maybeAddConfig for readability
7 participants