-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Fix agent config indicator when applied through fleet integration #131820
Changes from all commits
c92ba74
bab0ced
7329fe0
d50d06c
abae232
29efe60
44abd38
e62bbc2
74bd08c
8b76c61
57a3627
560c644
0aa86ff
1cea1ea
4f5b9de
e547c6f
4757af5
29205d6
b1f8d4e
5737fc0
e19ec2a
06171e3
d9b00bf
758d67a
e918b75
fc5fa66
9445e65
98f4ee4
f2cebe3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { AgentConfigFields } from './agent_config_fields'; | ||
import { Metricset } from '../apm/metricset'; | ||
|
||
export class AgentConfig extends Metricset<AgentConfigFields> { | ||
constructor() { | ||
super({ | ||
'metricset.name': 'agent_config', | ||
agent_config_applied: 1, | ||
}); | ||
} | ||
|
||
etag(etag: string) { | ||
this.fields['labels.etag'] = etag; | ||
return this; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { ApmFields } from '../apm/apm_fields'; | ||
|
||
export type AgentConfigFields = Pick< | ||
ApmFields, | ||
| '@timestamp' | ||
| 'processor.event' | ||
| 'processor.name' | ||
| 'metricset.name' | ||
| 'observer' | ||
| 'ecs.version' | ||
| 'event.ingested' | ||
> & | ||
Partial<{ | ||
'labels.etag': string; | ||
agent_config_applied: number; | ||
'event.agent_id_status': string; | ||
}>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
export { observer } from './observer'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { AgentConfigFields } from './agent_config_fields'; | ||
import { AgentConfig } from './agent_config'; | ||
import { Entity } from '../entity'; | ||
|
||
export class Observer extends Entity<AgentConfigFields> { | ||
agentConfig() { | ||
return new AgentConfig(); | ||
} | ||
} | ||
|
||
export function observer() { | ||
return new Observer({}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { observer, timerange } from '../..'; | ||
import { Scenario } from '../scenario'; | ||
import { getLogger } from '../utils/get_common_services'; | ||
import { RunOptions } from '../utils/parse_run_cli_flags'; | ||
import { AgentConfigFields } from '../../lib/agent_config/agent_config_fields'; | ||
|
||
const scenario: Scenario<AgentConfigFields> = async (runOptions: RunOptions) => { | ||
const logger = getLogger(runOptions); | ||
|
||
return { | ||
generate: ({ from, to }) => { | ||
const agentConfig = observer().agentConfig(); | ||
|
||
const range = timerange(from, to); | ||
return range | ||
.interval('30s') | ||
.rate(1) | ||
.generator((timestamp) => { | ||
const events = logger.perf('generating_agent_config_events', () => { | ||
return agentConfig.etag('test-etag').timestamp(timestamp); | ||
}); | ||
return events; | ||
}); | ||
}, | ||
}; | ||
}; | ||
|
||
export default scenario; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,17 +13,27 @@ import { AgentConfiguration } from '../../../../common/agent_configuration/confi | |
export function convertConfigSettingsToString( | ||
hit: SearchHit<AgentConfiguration> | ||
) { | ||
const config = hit._source; | ||
const { settings } = hit._source; | ||
|
||
if (config.settings?.transaction_sample_rate) { | ||
config.settings.transaction_sample_rate = | ||
config.settings.transaction_sample_rate.toString(); | ||
} | ||
const convertedConfigSettings = { | ||
...settings, | ||
...(settings?.transaction_sample_rate | ||
? { | ||
transaction_sample_rate: settings.transaction_sample_rate.toString(), | ||
} | ||
: {}), | ||
...(settings?.transaction_max_spans | ||
? { | ||
transaction_max_spans: settings.transaction_max_spans.toString(), | ||
} | ||
: {}), | ||
}; | ||
|
||
if (config.settings?.transaction_max_spans) { | ||
config.settings.transaction_max_spans = | ||
config.settings.transaction_max_spans.toString(); | ||
} | ||
|
||
return hit; | ||
return { | ||
...hit, | ||
_source: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if it matters much, but it does feel kind of gross that we're transforming There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel the same, looked to simplify it at first but it's used in the public API. |
||
...hit._source, | ||
settings: convertedConfigSettings, | ||
}, | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import { | |
} from '../../../../common/elasticsearch_fieldnames'; | ||
import { Setup } from '../../../lib/helpers/setup_request'; | ||
import { convertConfigSettingsToString } from './convert_settings_to_string'; | ||
import { getConfigsAppliedToAgentsThroughFleet } from './get_config_applied_to_agent_through_fleet'; | ||
|
||
export async function findExactConfiguration({ | ||
service, | ||
|
@@ -40,16 +41,27 @@ export async function findExactConfiguration({ | |
}, | ||
}; | ||
|
||
const resp = await internalClient.search<AgentConfiguration, typeof params>( | ||
'find_exact_agent_configuration', | ||
params | ||
); | ||
const [agentConfig, configsAppliedToAgentsThroughFleet] = await Promise.all([ | ||
internalClient.search<AgentConfiguration, typeof params>( | ||
'find_exact_agent_configuration', | ||
params | ||
), | ||
getConfigsAppliedToAgentsThroughFleet({ setup }), | ||
]); | ||
|
||
const hit = resp.hits.hits[0] as SearchHit<AgentConfiguration> | undefined; | ||
const hit = agentConfig.hits.hits[0] as | ||
| SearchHit<AgentConfiguration> | ||
| undefined; | ||
|
||
if (!hit) { | ||
return; | ||
} | ||
|
||
return convertConfigSettingsToString(hit); | ||
return { | ||
id: hit._id, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is new but it's not a breaking change as this function is only used in private APIs and in the function body of some public ones without changing the return type |
||
...convertConfigSettingsToString(hit)._source, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw, can you convert this function to be immutable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed in 4757af5 |
||
applied_by_agent: | ||
hit._source.applied_by_agent || | ||
configsAppliedToAgentsThroughFleet.hasOwnProperty(hit._source.etag), | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { termQuery, rangeQuery } from '@kbn/observability-plugin/server'; | ||
import datemath from '@kbn/datemath'; | ||
import { METRICSET_NAME } from '../../../../common/elasticsearch_fieldnames'; | ||
import { Setup } from '../../../lib/helpers/setup_request'; | ||
|
||
export async function getConfigsAppliedToAgentsThroughFleet({ | ||
setup, | ||
}: { | ||
setup: Setup; | ||
}) { | ||
const { internalClient, indices } = setup; | ||
|
||
const params = { | ||
index: indices.metric, | ||
size: 0, | ||
body: { | ||
query: { | ||
bool: { | ||
filter: [ | ||
...termQuery(METRICSET_NAME, 'agent_config'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious if this is the best way. Given it's a single There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah we also use it for a list of agent configurations. That means we cannot set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense, will do them in parallel There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 1cea1ea |
||
...rangeQuery( | ||
datemath.parse('now-15m')!.valueOf(), | ||
datemath.parse('now')!.valueOf() | ||
), | ||
], | ||
}, | ||
}, | ||
aggs: { | ||
config_by_etag: { | ||
terms: { | ||
field: 'labels.etag', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated in e547c6f |
||
size: 200, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
const response = await internalClient.search( | ||
'get_config_applied_to_agent_through_fleet', | ||
params | ||
); | ||
|
||
return ( | ||
response.aggregations?.config_by_etag.buckets.reduce( | ||
(configsAppliedToAgentsThroughFleet, bucket) => { | ||
configsAppliedToAgentsThroughFleet[bucket.key as string] = true; | ||
return configsAppliedToAgentsThroughFleet; | ||
}, | ||
{} as Record<string, true> | ||
) ?? {} | ||
); | ||
} |
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.
Is there another place preferred to set the data stream for these metrics? cc @Mpdreamz