Skip to content

Commit 04077ba

Browse files
authored
[9.1] [Synthetics] Return legacy monitor filters (#231562) (#232106)
# Backport This will backport the following commits from `main` to `9.1`: - [[Synthetics] Return legacy monitor filters (#231562)](#231562) <!--- Backport version: 10.0.1 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Francesco Fagnani","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-08-18T13:19:28Z","message":"[Synthetics] Return legacy monitor filters (#231562)","sha":"9046fd4d1e566ddffc7f6dc39cada9332d46117f","branchLabelMapping":{"^v9.2.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:obs-ux-management","backport:version","author:obs-ux-management","v9.2.0","v9.1.3","v8.19.3"],"title":"[Synthetics] Return legacy monitor filters","number":231562,"url":"https://github.com/elastic/kibana/pull/231562","mergeCommit":{"message":"[Synthetics] Return legacy monitor filters (#231562)","sha":"9046fd4d1e566ddffc7f6dc39cada9332d46117f"}},"sourceBranch":"main","suggestedTargetBranches":["9.1","8.19"],"targetPullRequestStates":[{"branch":"main","label":"v9.2.0","branchLabelMappingKey":"^v9.2.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/231562","number":231562,"mergeCommit":{"message":"[Synthetics] Return legacy monitor filters (#231562)","sha":"9046fd4d1e566ddffc7f6dc39cada9332d46117f"}},{"branch":"9.1","label":"v9.1.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.19","label":"v8.19.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
1 parent fadff51 commit 04077ba

File tree

2 files changed

+170
-55
lines changed
  • x-pack/solutions/observability
    • plugins/synthetics/server/routes/filters
    • test/api_integration_deployment_agnostic/apis/synthetics

2 files changed

+170
-55
lines changed

x-pack/solutions/observability/plugins/synthetics/server/routes/filters/filters.ts

Lines changed: 74 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
legacySyntheticsMonitorTypeSingle,
1111
syntheticsMonitorAttributes,
1212
syntheticsMonitorSavedObjectType,
13+
legacyMonitorAttributes,
1314
} from '../../../common/types/saved_objects';
1415
import { ConfigKey, MonitorFiltersResult } from '../../../common/runtime_types';
1516
import { SYNTHETICS_API_URLS } from '../../../common/constants';
@@ -20,23 +21,29 @@ type Buckets = Array<{
2021
}>;
2122

2223
interface AggsResponse {
23-
monitorTypes: {
24-
buckets: Buckets;
25-
};
26-
locations: {
27-
buckets: Buckets;
28-
};
29-
tags: {
30-
buckets: Buckets;
31-
};
32-
projects: {
33-
buckets: Buckets;
34-
};
35-
schedules: {
36-
buckets: Buckets;
37-
};
24+
monitorTypes?: { buckets: Buckets };
25+
monitorTypesLegacy?: { buckets: Buckets };
26+
locations?: { buckets: Buckets };
27+
locationsLegacy?: { buckets: Buckets };
28+
tags?: { buckets: Buckets };
29+
tagsLegacy?: { buckets: Buckets };
30+
projects?: { buckets: Buckets };
31+
projectsLegacy?: { buckets: Buckets };
32+
schedules?: { buckets: Buckets };
33+
schedulesLegacy?: { buckets: Buckets };
3834
}
3935

36+
const mergeBuckets = (...bucketSets: Array<Buckets | undefined>) => {
37+
const map = new Map<string, number>();
38+
for (const buckets of bucketSets) {
39+
buckets?.forEach(({ key, doc_count: docCount }) => {
40+
const k = String(key);
41+
map.set(k, (map.get(k) ?? 0) + docCount);
42+
});
43+
}
44+
return Array.from(map.entries()).map(([label, count]) => ({ label, count }));
45+
};
46+
4047
export const getSyntheticsFilters: SyntheticsRestApiRouteFactory<MonitorFiltersResult> = () => ({
4148
method: 'GET',
4249
path: SYNTHETICS_API_URLS.FILTERS,
@@ -54,36 +61,29 @@ export const getSyntheticsFilters: SyntheticsRestApiRouteFactory<MonitorFiltersR
5461
...(showFromAllSpaces ? { namespaces: ['*'] } : {}),
5562
});
5663

57-
const { monitorTypes, tags, locations, projects, schedules } =
58-
(data?.aggregations as AggsResponse) ?? {};
64+
const {
65+
monitorTypes,
66+
monitorTypesLegacy,
67+
tags,
68+
tagsLegacy,
69+
locations,
70+
locationsLegacy,
71+
projects,
72+
projectsLegacy,
73+
schedules,
74+
schedulesLegacy,
75+
} = (data?.aggregations as AggsResponse) ?? {};
76+
5977
return {
60-
monitorTypes:
61-
monitorTypes?.buckets?.map(({ key, doc_count: count }) => ({
62-
label: key,
63-
count,
64-
})) ?? [],
65-
tags:
66-
tags?.buckets?.map(({ key, doc_count: count }) => ({
67-
label: key,
68-
count,
69-
})) ?? [],
70-
locations:
71-
locations?.buckets?.map(({ key, doc_count: count }) => ({
72-
label: key,
73-
count,
74-
})) ?? [],
75-
projects:
76-
projects?.buckets
77-
?.filter(({ key }) => key)
78-
.map(({ key, doc_count: count }) => ({
79-
label: key,
80-
count,
81-
})) ?? [],
82-
schedules:
83-
schedules?.buckets?.map(({ key, doc_count: count }) => ({
84-
label: String(key),
85-
count,
86-
})) ?? [],
78+
monitorTypes: mergeBuckets(monitorTypes?.buckets, monitorTypesLegacy?.buckets),
79+
tags: mergeBuckets(tags?.buckets, tagsLegacy?.buckets),
80+
locations: mergeBuckets(locations?.buckets, locationsLegacy?.buckets),
81+
projects: mergeBuckets(projects?.buckets, projectsLegacy?.buckets).filter(
82+
({ label }) => label
83+
),
84+
schedules: mergeBuckets(schedules?.buckets, schedulesLegacy?.buckets).map(
85+
({ label, count }) => ({ label: String(label), count })
86+
),
8787
};
8888
},
8989
});
@@ -95,28 +95,58 @@ const aggs = {
9595
size: 10000,
9696
},
9797
},
98+
monitorTypesLegacy: {
99+
terms: {
100+
field: `${legacyMonitorAttributes}.${ConfigKey.MONITOR_TYPE}.keyword`,
101+
size: 10000,
102+
},
103+
},
98104
tags: {
99105
terms: {
100106
field: `${syntheticsMonitorAttributes}.${ConfigKey.TAGS}`,
101107
size: 10000,
102108
},
103109
},
110+
tagsLegacy: {
111+
terms: {
112+
field: `${legacyMonitorAttributes}.${ConfigKey.TAGS}`,
113+
size: 10000,
114+
},
115+
},
104116
locations: {
105117
terms: {
106118
field: `${syntheticsMonitorAttributes}.${ConfigKey.LOCATIONS}.id`,
107119
size: 10000,
108120
},
109121
},
122+
locationsLegacy: {
123+
terms: {
124+
field: `${legacyMonitorAttributes}.${ConfigKey.LOCATIONS}.id`,
125+
size: 10000,
126+
},
127+
},
110128
projects: {
111129
terms: {
112130
field: `${syntheticsMonitorAttributes}.${ConfigKey.PROJECT_ID}`,
113131
size: 10000,
114132
},
115133
},
134+
projectsLegacy: {
135+
terms: {
136+
field: `${legacyMonitorAttributes}.${ConfigKey.PROJECT_ID}`,
137+
size: 10000,
138+
},
139+
},
116140
schedules: {
117141
terms: {
118142
field: `${syntheticsMonitorAttributes}.${ConfigKey.SCHEDULE}.number`,
119143
size: 10000,
120144
},
121145
},
146+
schedulesLegacy: {
147+
terms: {
148+
field: `${legacyMonitorAttributes}.${ConfigKey.SCHEDULE}.number`,
149+
size: 10000,
150+
},
151+
},
122152
};

x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/synthetics/get_filters.ts

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants';
99
import { RoleCredentials } from '@kbn/ftr-common-functional-services';
1010
import expect from '@kbn/expect';
11-
import { PrivateLocation } from '@kbn/synthetics-plugin/common/runtime_types';
12-
import { syntheticsMonitorSavedObjectType } from '@kbn/synthetics-plugin/common/types/saved_objects';
13-
import { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context';
11+
import type { PrivateLocation } from '@kbn/synthetics-plugin/common/runtime_types';
12+
import {
13+
legacySyntheticsMonitorTypeSingle,
14+
syntheticsMonitorSavedObjectType,
15+
} from '@kbn/synthetics-plugin/common/types/saved_objects';
16+
import type { DeploymentAgnosticFtrProviderContext } from '../../ftr_provider_context';
1417
import { PrivateLocationTestService } from '../../services/synthetics_private_location';
18+
import { addMonitorAPIHelper } from './create_monitor';
1519

1620
export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
1721
describe('getMonitorFilters', function () {
@@ -25,15 +29,23 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
2529
let privateLocation: PrivateLocation;
2630

2731
after(async () => {
28-
await kibanaServer.savedObjects.clean({ types: [syntheticsMonitorSavedObjectType] });
32+
await kibanaServer.savedObjects.clean({
33+
types: [syntheticsMonitorSavedObjectType, legacySyntheticsMonitorTypeSingle],
34+
});
2935
});
3036

3137
before(async () => {
32-
await kibanaServer.savedObjects.clean({ types: [syntheticsMonitorSavedObjectType] });
38+
await kibanaServer.savedObjects.clean({
39+
types: [syntheticsMonitorSavedObjectType, legacySyntheticsMonitorTypeSingle],
40+
});
3341
editorUser = await samlAuth.createM2mApiKeyWithRoleScope('editor');
3442
privateLocation = await privateLocationTestService.addTestPrivateLocation();
3543
});
3644

45+
const addMonitor = async (monitor: any, type?: string) => {
46+
return addMonitorAPIHelper(supertest, monitor, 200, editorUser, samlAuth, false, type);
47+
};
48+
3749
it('get list of filters', async () => {
3850
const apiResponse = await supertest
3951
.get(SYNTHETICS_API_URLS.FILTERS)
@@ -59,12 +71,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
5971
locations: [privateLocation],
6072
};
6173

62-
await supertest
63-
.post(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS)
64-
.set(editorUser.apiKeyHeader)
65-
.set(samlAuth.getInternalRequestHeader())
66-
.send(newMonitor)
67-
.expect(200);
74+
await addMonitor(newMonitor);
6875

6976
const apiResponse = await supertest
7077
.get(SYNTHETICS_API_URLS.FILTERS)
@@ -83,5 +90,83 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) {
8390
schedules: [{ label: '3', count: 1 }],
8491
});
8592
});
93+
94+
it('get list of filters for legacy saved object type monitor', async () => {
95+
// Create a legacy monitor directly via savedObjectsClient
96+
97+
// Use the internal savedObjectsClient to create a legacy monitor
98+
await addMonitor(
99+
{
100+
name: 'Legacy Monitor',
101+
type: 'icmp',
102+
host: 'https://legacy.elastic.co',
103+
tags: ['legacy', 'synthetics'],
104+
locations: [privateLocation],
105+
},
106+
legacySyntheticsMonitorTypeSingle
107+
);
108+
109+
const apiResponse = await supertest
110+
.get(SYNTHETICS_API_URLS.FILTERS)
111+
.set(editorUser.apiKeyHeader)
112+
.set(samlAuth.getInternalRequestHeader())
113+
.expect(200);
114+
115+
expect(apiResponse.body.monitorTypes).to.eql([
116+
{ label: 'http', count: 1 },
117+
{ label: 'icmp', count: 1 },
118+
]);
119+
expect(apiResponse.body.tags).to.eql([
120+
{ label: 'apm', count: 1 },
121+
{ label: 'synthetics', count: 2 },
122+
{ label: 'legacy', count: 1 },
123+
]);
124+
expect(apiResponse.body.locations).to.eql([{ label: privateLocation.id, count: 2 }]);
125+
expect(apiResponse.body.schedules).to.eql([{ label: '3', count: 2 }]);
126+
});
127+
128+
it('get list of filters with both legacy and modern monitors', async () => {
129+
// Create a modern monitor
130+
const modernMonitor = {
131+
name: 'Modern Monitor',
132+
type: 'http',
133+
urls: 'https://modern.elastic.co',
134+
tags: ['multi-space', 'synthetics'],
135+
locations: [privateLocation],
136+
};
137+
138+
await addMonitor(modernMonitor);
139+
140+
await addMonitor(
141+
{
142+
name: 'Legacy Monitor 3',
143+
type: 'icmp',
144+
host: 'https://legacy2.elastic.co',
145+
tags: ['legacy2', 'synthetics'],
146+
locations: [privateLocation],
147+
},
148+
legacySyntheticsMonitorTypeSingle
149+
);
150+
151+
const apiResponse = await supertest
152+
.get(SYNTHETICS_API_URLS.FILTERS)
153+
.set(editorUser.apiKeyHeader)
154+
.set(samlAuth.getInternalRequestHeader())
155+
.expect(200);
156+
157+
expect(apiResponse.body.monitorTypes).to.eql([
158+
{ label: 'http', count: 2 },
159+
{ label: 'icmp', count: 2 },
160+
]);
161+
expect(apiResponse.body.tags).to.eql([
162+
{ label: 'synthetics', count: 4 },
163+
{ label: 'apm', count: 1 },
164+
{ label: 'multi-space', count: 1 },
165+
{ label: 'legacy', count: 1 },
166+
{ label: 'legacy2', count: 1 },
167+
]);
168+
expect(apiResponse.body.locations).to.eql([{ label: privateLocation.id, count: 4 }]);
169+
expect(apiResponse.body.schedules).to.eql([{ label: '3', count: 4 }]);
170+
});
86171
});
87172
}

0 commit comments

Comments
 (0)