-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
[APM] Migrate server routes to NP #49455
Conversation
💔 Build Failed
|
85ac256
to
1945cd6
Compare
💔 Build Failed
|
Legacy vs NP configThere's two options, either you keep the duplicated legacy schema around until all dependencies have moved away from Legacy. Or you migrate the dependencies to pull these config values from the NP plugin for them. For instance I saw infra uses legacy config to get the apmIndex. The code below doesn't work cause there's no If there's not a lot of places depending on this legacy config, it's probably best to go all out and only keep the NP config, changing all legacy plugins to consume this NP plugins' configuration. diff --git a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/has_apm_data.ts b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/has_apm_data.ts
index 3193cf8397..7b91e67ea2 100644
--- a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/has_apm_data.ts
+++ b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/has_apm_data.ts
@@ -19,7 +19,11 @@ export const hasAPMData = async (
nodeType: 'host' | 'pod' | 'container'
) => {
const config = framework.config(req);
- const apmIndex = config.get('apm_oss.transactionIndices') || 'apm-*';
+ // You'll probably want to extract apmConfig in infra's init.ts and then
+ // inject it into this function (through framework?)
+ const apmConfig = await server.newPlatform.setup.plugins.apm_oss.config$.toPromise();
+ const apmIndex = apmConfig.transactionIndices || 'apm-*';
+
// There is a bug in APM ECS data where host.name is not set.
// This will fixed with: https://github.com/elastic/apm-server/issues/2502
const nodeFieldName = Server.usageWill be replaced by the metrics plugin in NP #46924 the stack services team is responsible for this, I think they're targeting 7.6 |
1945cd6
to
7e53af7
Compare
💔 Build Failed
|
7e53af7
to
112cf00
Compare
💔 Build Failed
|
@elasticmachine merge upstream |
merge conflict between base and head |
112cf00
to
0591d08
Compare
@elasticmachine merge upstream |
💔 Build Failed
|
@elasticmachine merge upstream |
💔 Build Failed
|
b24e7b2
to
6b597e1
Compare
6b597e1
to
e5b6590
Compare
I moved this out of draft prematurely. I still have to figure out how to create an internal saved objects client. |
💔 Build Failed
|
💔 Build Failed
|
25e8004
to
c0d153a
Compare
💚 Build Succeeded
|
uiFiltersES: ESFilter[]; | ||
}; | ||
|
||
export type SetupWithAllFilters = SetupWithTimeRange & SetupWithUIFilters; |
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 not sure this'll work longer term. What happens when we add a new property that not every route needs? Then it's not "all" anymore.
Perhaps it's better to be explicit and type it in place as: Setup & TimeRange & UIFilters
.
Not for this PR but: Setup
itself is already pretty opaque. It contains a bunch of different stuff - perhaps it would make sense to split that up into smaller parts 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.
++ on separating Setup{WithTimeRange,WithUIFilters} and using TS unions. Composable & explicit. Fixed.
I'd think it'd be good to think (at some point) about APMRequestContext and SetupRequest, how they overlap, how they are different, and possibly if we need a APMPluginContract or something similar as well. Maybe after NP migration is completed?
} | ||
} | ||
} | ||
} as unknown) as APMRequestHandlerContext; |
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.
What do you think about creating the saved objects client on Setup
like we do with client
and internalClient
. then we could have savedObjectsClient
and internalSavedObjectsClient
. This way we wouldn't have to pass context around anymore.
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.
context
is still needed for config
and some other stuff, or am I misunderstanding? the internal saved objects client is a WIP, maybe better to wait? #48882
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.
config
is already on Setup
. I'm thinking that it would be nice if downstream handlers don't have to know about Context
or Request
- at least if they are just doing normal stuff like reading config, calling (internal) savedobjects or (internal) esClient.
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.
Right, I see what you mean. Ok if I create an issue for this that we can pick up after the migration to NP is complete (including the usage collector and the internal saved objects client)?
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.
Went ahead and created the issue: #51257
x-pack/legacy/plugins/apm/server/lib/index_pattern/get_dynamic_index_pattern.ts
Show resolved
Hide resolved
export async function getServices(setup: SetupWithAllFilters) { | ||
const itemsPromise = getServicesItems(setup); | ||
const hasLegacyDataPromise = getLegacyDataStatus(setup); | ||
const items = await itemsPromise; |
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.
Any reason for not await
'ing immediately? This ends up being await
'ed in serial endyway.
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.
getLegacyDataStatus
(2) is not blocked by getServicesItems
(1), only hasHistoricalAgentData
(3) is. So this starts 1 and 2 immediately, and if 1 finishes, 3 starts. Then the function returns when all promises are resolved. At least, that's what it should do. Do you see something else happening?
I could also rewrite with promises if it makes more sense:
const [{ items, hasHistoricalData }, hasLegacyData] = await Promise.all([
getServicesItems(setup).then(async servicesItems => {
const noDataInCurrentTimeRange = isEmpty(servicesItems);
return {
items: servicesItems,
hasHistoricalData: noDataInCurrentTimeRange
? await hasHistoricalAgentData(setup)
: true
};
}),
getLegacyDataStatus(setup)
]);
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.
Maybe I'm missing something but isn't this equivalent to using Promise.all
for the first two promises?
export async function getServices(setup: SetupWithAllFilters) {
const [items, hasLegacyData] = await Promise.all([
getServicesItems(setup),
getLegacyDataStatus(setup)
]);
const noDataInCurrentTimeRange = isEmpty(items);
const hasHistoricalData = noDataInCurrentTimeRange
? await hasHistoricalAgentData(setup)
: true;
return {
items,
hasHistoricalData,
hasLegacyData
};
}
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.
At least this approach is more clear to 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.
getServicesItems
could finish before getLegacyDataStatus
and then the latter would unnecessary block hasHistoricalAgentData
, right? (hasHistoricalAgentData
needs getServicesItems
, but not hasLegacyData
)
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.
Maybe it's not worth it though? I do think the version that we have today is more readable for sure.
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.
getServicesItems
could finish beforegetLegacyDataStatus
and then the latter would unnecessary blockhasHistoricalAgentData
, right?
Did you time this? I'd expect in most cases getLegacyDataStatus
to be faster than getServicesItems
- ofc this depends on both the selected time range and the data volumes.
Regardless, I think the difference is negligible and I'd optimize for the most readable version.
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 didn't time it, I figured it would be a win anyway but agreed, let's keep it simple 👍
x-pack/legacy/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts
Show resolved
Hide resolved
x-pack/plugins/apm/server/index.ts
Outdated
schema: schema.object({ | ||
servicemapEnabled: schema.boolean({ defaultValue: false }), | ||
bucketTargetCount: schema.number({ defaultValue: 15 }), | ||
minimumBucketSize: schema.number({ defaultValue: 15 }), |
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.
minimumBucketSize
and bucketTargetCount
are carry-over from the opbeat days (yeah!).
If you think it makes sense in this PR it would be great if you can just make them constants (like apmAgentConfigurationIndex
)
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.
Moved these to plain old constants in the server/lib/transactions/constants
. They're not used outside of transactions AFAICT.
c0d153a
to
c322965
Compare
💚 Build Succeeded
|
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.
looks great only a few nitpicks around how we can handle context, Setup etc.
Closes elastic#49238. Pass legacy API to NP plugin in order to use internal SO client Fix issues with agent configuration APIs Update tsconfig template for TS optimization Fix typo
fdf6efa
to
5bf33fd
Compare
💔 Build Failed |
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.
Left some small suggestions, but all in all this looks great!
config: APMConfig; | ||
logger: Logger; | ||
__LEGACY: { | ||
server: Server; |
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: You're using a really broad type here which makes it hard to see which dependencies you're using. I would suggest just typing the dependencies you're using like:
__LEGACY: {
server: {
savedObjects: {
getScopedSavedObjectsClient: Server['savedObjects']['getScopedSavedObjectsClient']
}
// similar for usage collector
}
}
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.
Good one, I've narrowed the type to the things that we are using at the moment.
import { once } from 'lodash'; | ||
import { Plugin as APMOSSPlugin } from '../../../../src/plugins/apm_oss/server'; | ||
import { createApmAgentConfigurationIndex } from '../../../legacy/plugins/apm/server/lib/settings/agent_configuration/create_agent_config_index'; | ||
import { createApmApi } from '../../../legacy/plugins/apm/server/routes/create_apm_api'; |
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: it's a bit confusing when you have routes in a legacy plugin, being run from a NP plugin, but injecting dependencies from a legacy plugin, just kinda hard to wrap your head around. Do you still need these files in legacy or could you move create_apm_api and all the routes into the NP plugin?
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 think this makes more sense to do when the migration is completed. Otherwise legacy will import lots of stuff from np and the other way around. I've added it to the list in #32894
💚 Build Succeeded |
* [APM] Migrate server routes to NP Closes #49238. Pass legacy API to NP plugin in order to use internal SO client Fix issues with agent configuration APIs Update tsconfig template for TS optimization Fix typo * Review feedback * Fix type issues after browser duration changes * Revert changes in getServices due to readability concerns * Review feedback
Closes #49238.
Closes #51156
Changes:
createApmApi
andcreateApmAgentConfiguration
to NP. Not sure how to movemakeApmUsageSelector
as it depends onserver.usage
.( request:hapi.Request, params:Params, h:hapi.ResponseToolkit )
to( kibanaContext:{ context: APMRequestHandlerContext, request: Kibana.Request } )
.APMRequestHandlerContext
isKibana.RequestHandlerContext
plus the APM configuration and the decoded request parameters.TODOs/questions (cc @rudolf):
TheCopying and pasting stuff for now.apm
/apm_oss
legacy configurations are used by infra and the tutorial. In this PR, we have two schemas, one for NP with@kbn/config-schema
, and one for LP withJoi
. Is there a way we can prevent this duplication (and still expose legacy configuration values)?We are using io-ts for validation route input. NP requires a schema fromPlatform will enable support for@kbn/config-schema
. Right now we're using a noop schema as a workaround, but it's not pretty. Any thoughts on how this could be better?io-ts
in the near future, see Decouple request validation from @kbn/config-schema #50179What is the replacement forBlocked by collectorSets in the New Platform #46924. Left in legacy plugin for now.server.usage
?