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
Serve.js refactors #158750
Conversation
88b13ce
to
0cc569a
Compare
0cc569a
to
b9cb27a
Compare
There was a problem hiding this 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.
src/cli/serve/serve.js
Outdated
configs.unshift(resolveConfig(`serverless.${serverlessMode}.yml`)); | ||
configs.unshift(resolveConfig('serverless.yml')); | ||
|
||
if (opts.dev) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
// 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(); | ||
} | ||
|
There was a problem hiding this comment.
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 🧡
src/cli/serve/serve.js
Outdated
if (opts.dev) { | ||
configs.push(resolveConfig('serverless.dev.yml')); | ||
|
||
writeProjectSwitcherConfig('serverless.recent.dev.yml'); |
There was a problem hiding this 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 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
configs.push(resolveConfig('serverless.dev.yml')); | ||
|
||
writeProjectSwitcherConfig('serverless.recent.dev.yml'); | ||
configs.push(resolveConfig('serverless.recent.dev.yml')); |
There was a problem hiding this comment.
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.
src/cli/serve/serve.js
Outdated
// Filtering out all config paths that didn't exist | ||
configs = configs.filter(Boolean); | ||
|
||
const serverlessMode = getServerlessModeFromOpts(opts) || getServerlessModeFromCfg(configs); |
There was a problem hiding this comment.
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:
- Dev starts Kibana with
yarn start --serverless
(no project specified) - The first time, Project Switcher defaults to
es
✅. Otherwise, it checks the latest project type it was running (it was stored inserverless.recent.yml
) 🛑 with this approach,opts.serverless === true
will always returnes
. - While running Kibana, the developer could switch the project type.
POST /internal/serverless/switch_project
would write the selected project type inserverless.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 😇
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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
@elasticmachine merge upstream |
Pinging @elastic/kibana-operations (Team:Operations) |
@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. |
There was a problem hiding this 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(', ')); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
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.
There was a problem hiding this comment.
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 :-)
There was a problem hiding this comment.
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 :)
if (dev && devConfig !== false) { | ||
configs.push(resolveConfig('serverless.dev.yml')); | ||
configs.push(resolveConfig(`serverless.${serverlessMode}.dev.yml`)); | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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:
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.
There was a problem hiding this comment.
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
)
There was a problem hiding this comment.
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.
if (serverlessMode === true) { | ||
// Defaulting to read the project-switcher's settings in `serverless.recent.dev.yml` | ||
return null; | ||
} |
There was a problem hiding this comment.
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'), |
There was a problem hiding this comment.
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
💚 Build Succeeded
Metrics [docs]Unknown metric groupsESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: |
There was a problem hiding this 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
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>
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>
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>
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>
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 configsbootstrap.ts
can be agnostic of the config stack, just receive it, and use itUnit tests for
compileConfigStack
This replaces integration tests around
serve.js
andbootstrap.ts
that examine config lists w/r/t serverless.Checklist