mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Synthetics] Handle private locations simultaneous edits !! (#195874)](https://github.com/elastic/kibana/pull/195874) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Shahzad","email":"shahzad31comp@gmail.com"},"sourceCommit":{"committedDate":"2024-11-07T21:31:09Z","message":"[Synthetics] Handle private locations simultaneous edits !! (#195874)\n\n## Summary\r\n\r\nFixes https://github.com/elastic/kibana/issues/190801 !!\r\n\r\nHandle private locations simultaneous edits !! \r\n\r\nRegistered a new saved object to handle private locations properly.\r\nInstead of using a singleton, now each private location will be\r\nrepresented by it's own saved object.\r\n\r\n### Existing private locations\r\nWhen we are doing any write operation, we migrate them to new kind of\r\nsaved object and remove the legacy saved object type.\r\n\r\n\r\n### Testing\r\n\r\n- Create multiple private locations on main \r\n- Switch to branch and create few more locations\r\n- Make sure all private locations are editable, deleteable and have been\r\nmigrated to new saved object types in the course\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"96c9b5b5d0a82c6e4b0a9b86fc1ab4dd9fa4d707","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","v9.0.0","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-management"],"title":"[Synthetics] Handle private locations simultaneous edits !!","number":195874,"url":"https://github.com/elastic/kibana/pull/195874","mergeCommit":{"message":"[Synthetics] Handle private locations simultaneous edits !! (#195874)\n\n## Summary\r\n\r\nFixes https://github.com/elastic/kibana/issues/190801 !!\r\n\r\nHandle private locations simultaneous edits !! \r\n\r\nRegistered a new saved object to handle private locations properly.\r\nInstead of using a singleton, now each private location will be\r\nrepresented by it's own saved object.\r\n\r\n### Existing private locations\r\nWhen we are doing any write operation, we migrate them to new kind of\r\nsaved object and remove the legacy saved object type.\r\n\r\n\r\n### Testing\r\n\r\n- Create multiple private locations on main \r\n- Switch to branch and create few more locations\r\n- Make sure all private locations are editable, deleteable and have been\r\nmigrated to new saved object types in the course\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"96c9b5b5d0a82c6e4b0a9b86fc1ab4dd9fa4d707"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/195874","number":195874,"mergeCommit":{"message":"[Synthetics] Handle private locations simultaneous edits !! (#195874)\n\n## Summary\r\n\r\nFixes https://github.com/elastic/kibana/issues/190801 !!\r\n\r\nHandle private locations simultaneous edits !! \r\n\r\nRegistered a new saved object to handle private locations properly.\r\nInstead of using a singleton, now each private location will be\r\nrepresented by it's own saved object.\r\n\r\n### Existing private locations\r\nWhen we are doing any write operation, we migrate them to new kind of\r\nsaved object and remove the legacy saved object type.\r\n\r\n\r\n### Testing\r\n\r\n- Create multiple private locations on main \r\n- Switch to branch and create few more locations\r\n- Make sure all private locations are editable, deleteable and have been\r\nmigrated to new saved object types in the course\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"96c9b5b5d0a82c6e4b0a9b86fc1ab4dd9fa4d707"}}]}] BACKPORT--> Co-authored-by: Shahzad <shahzad31comp@gmail.com>
This commit is contained in:
parent
de09e3af76
commit
afb795de1a
42 changed files with 576 additions and 327 deletions
|
@ -1072,6 +1072,7 @@
|
|||
"urls"
|
||||
],
|
||||
"synthetics-param": [],
|
||||
"synthetics-private-location": [],
|
||||
"synthetics-privates-locations": [],
|
||||
"tag": [
|
||||
"color",
|
||||
|
|
|
@ -3549,6 +3549,10 @@
|
|||
"dynamic": false,
|
||||
"properties": {}
|
||||
},
|
||||
"synthetics-private-location": {
|
||||
"dynamic": false,
|
||||
"properties": {}
|
||||
},
|
||||
"synthetics-privates-locations": {
|
||||
"dynamic": false,
|
||||
"properties": {}
|
||||
|
|
|
@ -109,6 +109,7 @@ const STANDARD_LIST_TYPES = [
|
|||
'synthetics-monitor',
|
||||
'uptime-dynamic-settings',
|
||||
'synthetics-privates-locations',
|
||||
'synthetics-private-location',
|
||||
|
||||
'osquery-saved-query',
|
||||
'osquery-pack',
|
||||
|
|
|
@ -165,6 +165,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
|
|||
"synthetics-dynamic-settings": "4b40a93eb3e222619bf4e7fe34a9b9e7ab91a0a7",
|
||||
"synthetics-monitor": "5ceb25b6249bd26902c9b34273c71c3dce06dbea",
|
||||
"synthetics-param": "3ebb744e5571de678b1312d5c418c8188002cf5e",
|
||||
"synthetics-private-location": "8cecc9e4f39637d2f8244eb7985c0690ceab24be",
|
||||
"synthetics-privates-locations": "f53d799d5c9bc8454aaa32c6abc99a899b025d5c",
|
||||
"tag": "e2544392fe6563e215bb677abc8b01c2601ef2dc",
|
||||
"task": "3c89a7c918d5b896a5f8800f06e9114ad7e7aea3",
|
||||
|
|
|
@ -139,6 +139,7 @@ const previouslyRegisteredTypes = [
|
|||
'synthetics-monitor',
|
||||
'synthetics-param',
|
||||
'synthetics-privates-locations',
|
||||
'synthetics-private-location',
|
||||
'tag',
|
||||
'task',
|
||||
'telemetry',
|
||||
|
|
|
@ -5,5 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export const privateLocationsSavedObjectId = 'synthetics-privates-locations-singleton';
|
||||
export const privateLocationsSavedObjectName = 'synthetics-privates-locations';
|
||||
export const legacyPrivateLocationsSavedObjectId = 'synthetics-privates-locations-singleton';
|
||||
export const legacyPrivateLocationsSavedObjectName = 'synthetics-privates-locations';
|
||||
|
||||
export const privateLocationSavedObjectName = 'synthetics-private-location';
|
||||
|
|
|
@ -7,17 +7,14 @@
|
|||
|
||||
import { journey, step, before, after, expect } from '@elastic/synthetics';
|
||||
import { waitForLoadingToFinish } from '@kbn/ux-plugin/e2e/journeys/utils';
|
||||
import { SyntheticsServices } from './services/synthetics_services';
|
||||
import { byTestId } from '../../helpers/utils';
|
||||
import {
|
||||
addTestMonitor,
|
||||
cleanPrivateLocations,
|
||||
cleanTestMonitors,
|
||||
getPrivateLocations,
|
||||
} from './services/add_monitor';
|
||||
import { addTestMonitor, cleanPrivateLocations, cleanTestMonitors } from './services/add_monitor';
|
||||
import { syntheticsAppPageProvider } from '../page_objects/synthetics_app';
|
||||
|
||||
journey(`PrivateLocationsSettings`, async ({ page, params }) => {
|
||||
const syntheticsApp = syntheticsAppPageProvider({ page, kibanaUrl: params.kibanaUrl, params });
|
||||
const services = new SyntheticsServices(params);
|
||||
|
||||
page.setDefaultTimeout(2 * 30000);
|
||||
|
||||
|
@ -78,16 +75,14 @@ journey(`PrivateLocationsSettings`, async ({ page, params }) => {
|
|||
await page.click('text=Private Locations');
|
||||
await page.click('h1:has-text("Settings")');
|
||||
|
||||
const privateLocations = await getPrivateLocations(params);
|
||||
const privateLocations = await services.getPrivateLocations();
|
||||
|
||||
const locations = privateLocations.attributes.locations;
|
||||
expect(privateLocations.length).toBe(1);
|
||||
|
||||
expect(locations.length).toBe(1);
|
||||
|
||||
locationId = locations[0].id;
|
||||
locationId = privateLocations[0].id;
|
||||
|
||||
await addTestMonitor(params.kibanaUrl, 'test-monitor', {
|
||||
locations: [locations[0]],
|
||||
locations: [privateLocations[0]],
|
||||
type: 'browser',
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
|
||||
import axios from 'axios';
|
||||
import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants';
|
||||
import {
|
||||
privateLocationsSavedObjectId,
|
||||
privateLocationsSavedObjectName,
|
||||
} from '@kbn/synthetics-plugin/common/saved_objects/private_locations';
|
||||
import { legacyPrivateLocationsSavedObjectName } from '@kbn/synthetics-plugin/common/saved_objects/private_locations';
|
||||
|
||||
export const enableMonitorManagedViaApi = async (kibanaUrl: string) => {
|
||||
try {
|
||||
|
@ -46,21 +43,6 @@ export const addTestMonitor = async (
|
|||
}
|
||||
};
|
||||
|
||||
export const getPrivateLocations = async (params: Record<string, any>) => {
|
||||
const getService = params.getService;
|
||||
const server = getService('kibanaServer');
|
||||
|
||||
try {
|
||||
return await server.savedObjects.get({
|
||||
id: privateLocationsSavedObjectId,
|
||||
type: privateLocationsSavedObjectName,
|
||||
});
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const cleanTestMonitors = async (params: Record<string, any>) => {
|
||||
const getService = params.getService;
|
||||
const server = getService('kibanaServer');
|
||||
|
@ -79,7 +61,11 @@ export const cleanPrivateLocations = async (params: Record<string, any>) => {
|
|||
|
||||
try {
|
||||
await server.savedObjects.clean({
|
||||
types: [privateLocationsSavedObjectName, 'ingest-agent-policies', 'ingest-package-policies'],
|
||||
types: [
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
'ingest-agent-policies',
|
||||
'ingest-package-policies',
|
||||
],
|
||||
});
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
|
|
@ -10,7 +10,10 @@ import type { Client } from '@elastic/elasticsearch';
|
|||
import { KbnClient } from '@kbn/test';
|
||||
import pMap from 'p-map';
|
||||
import { makeDownSummary, makeUpSummary } from '@kbn/observability-synthetics-test-data';
|
||||
import { SyntheticsMonitor } from '@kbn/synthetics-plugin/common/runtime_types';
|
||||
import {
|
||||
SyntheticsMonitor,
|
||||
SyntheticsPrivateLocations,
|
||||
} from '@kbn/synthetics-plugin/common/runtime_types';
|
||||
import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants';
|
||||
import { journeyStart, journeySummary, step1, step2 } from './data/browser_docs';
|
||||
|
||||
|
@ -251,4 +254,12 @@ export class SyntheticsServices {
|
|||
});
|
||||
return connector.data;
|
||||
}
|
||||
|
||||
async getPrivateLocations(): Promise<SyntheticsPrivateLocations> {
|
||||
const response = await this.requester.request({
|
||||
path: SYNTHETICS_API_URLS.PRIVATE_LOCATIONS,
|
||||
method: 'GET',
|
||||
});
|
||||
return response.data as SyntheticsPrivateLocations;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@ import {
|
|||
import { KibanaFeatureScope } from '@kbn/features-plugin/common';
|
||||
import { syntheticsMonitorType, syntheticsParamType } from '../common/types/saved_objects';
|
||||
import { SYNTHETICS_RULE_TYPES } from '../common/constants/synthetics_alerts';
|
||||
import { privateLocationsSavedObjectName } from '../common/saved_objects/private_locations';
|
||||
import {
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
privateLocationSavedObjectName,
|
||||
} from '../common/saved_objects/private_locations';
|
||||
import { PLUGIN } from '../common/constants/plugin';
|
||||
import {
|
||||
syntheticsSettingsObjectType,
|
||||
|
@ -71,7 +74,8 @@ export const syntheticsFeature = {
|
|||
syntheticsSettingsObjectType,
|
||||
syntheticsMonitorType,
|
||||
syntheticsApiKeyObjectType,
|
||||
privateLocationsSavedObjectName,
|
||||
privateLocationSavedObjectName,
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
syntheticsParamType,
|
||||
// uptime settings object is also registered here since feature is shared between synthetics and uptime
|
||||
uptimeSettingsObjectType,
|
||||
|
@ -102,7 +106,7 @@ export const syntheticsFeature = {
|
|||
syntheticsSettingsObjectType,
|
||||
syntheticsMonitorType,
|
||||
syntheticsApiKeyObjectType,
|
||||
privateLocationsSavedObjectName,
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
// uptime settings object is also registered here since feature is shared between synthetics and uptime
|
||||
uptimeSettingsObjectType,
|
||||
],
|
||||
|
|
|
@ -33,6 +33,16 @@ describe('syncEditedMonitor', () => {
|
|||
bulkUpdate: jest.fn(),
|
||||
get: jest.fn(),
|
||||
update: jest.fn(),
|
||||
createPointInTimeFinder: jest.fn().mockImplementation(({ perPage, type: soType }) => ({
|
||||
close: jest.fn(async () => {}),
|
||||
find: jest.fn().mockReturnValue({
|
||||
async *[Symbol.asyncIterator]() {
|
||||
yield {
|
||||
saved_objects: [],
|
||||
};
|
||||
},
|
||||
}),
|
||||
})),
|
||||
},
|
||||
logger,
|
||||
config: {
|
||||
|
|
|
@ -6,14 +6,12 @@
|
|||
*/
|
||||
|
||||
import { schema, TypeOf } from '@kbn/config-schema';
|
||||
import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations';
|
||||
import { SyntheticsRestApiRouteFactory } from '../../types';
|
||||
import { getPrivateLocationsAndAgentPolicies } from './get_private_locations';
|
||||
import {
|
||||
privateLocationsSavedObjectId,
|
||||
privateLocationsSavedObjectName,
|
||||
} from '../../../../common/saved_objects/private_locations';
|
||||
import { privateLocationSavedObjectName } from '../../../../common/saved_objects/private_locations';
|
||||
import { SYNTHETICS_API_URLS } from '../../../../common/constants';
|
||||
import type { SyntheticsPrivateLocationsAttributes } from '../../../runtime_types/private_locations';
|
||||
import { PrivateLocationAttributes } from '../../../runtime_types/private_locations';
|
||||
import { toClientContract, toSavedObjectContract } from './helpers';
|
||||
import { PrivateLocation } from '../../../../common/runtime_types';
|
||||
|
||||
|
@ -40,7 +38,11 @@ export const addPrivateLocationRoute: SyntheticsRestApiRouteFactory<PrivateLocat
|
|||
body: PrivateLocationSchema,
|
||||
},
|
||||
},
|
||||
handler: async ({ response, request, savedObjectsClient, syntheticsMonitorClient }) => {
|
||||
handler: async (routeContext) => {
|
||||
await migrateLegacyPrivateLocations(routeContext);
|
||||
|
||||
const { response, request, savedObjectsClient, syntheticsMonitorClient } = routeContext;
|
||||
|
||||
const location = request.body as PrivateLocationObject;
|
||||
|
||||
const { locations, agentPolicies } = await getPrivateLocationsAndAgentPolicies(
|
||||
|
@ -65,7 +67,6 @@ export const addPrivateLocationRoute: SyntheticsRestApiRouteFactory<PrivateLocat
|
|||
});
|
||||
}
|
||||
|
||||
const existingLocations = locations.filter((loc) => loc.id !== location.agentPolicyId);
|
||||
const formattedLocation = toSavedObjectContract({
|
||||
...location,
|
||||
id: location.agentPolicyId,
|
||||
|
@ -80,17 +81,17 @@ export const addPrivateLocationRoute: SyntheticsRestApiRouteFactory<PrivateLocat
|
|||
});
|
||||
}
|
||||
|
||||
const result = await savedObjectsClient.create<SyntheticsPrivateLocationsAttributes>(
|
||||
privateLocationsSavedObjectName,
|
||||
{ locations: [...existingLocations, formattedLocation] },
|
||||
const soClient = routeContext.server.coreStart.savedObjects.createInternalRepository();
|
||||
|
||||
const result = await soClient.create<PrivateLocationAttributes>(
|
||||
privateLocationSavedObjectName,
|
||||
formattedLocation,
|
||||
{
|
||||
id: privateLocationsSavedObjectId,
|
||||
overwrite: true,
|
||||
id: location.agentPolicyId,
|
||||
initialNamespaces: ['*'],
|
||||
}
|
||||
);
|
||||
|
||||
const allLocations = toClientContract(result.attributes, agentPolicies);
|
||||
|
||||
return allLocations.find((loc) => loc.id === location.agentPolicyId)!;
|
||||
return toClientContract(result.attributes, agentPolicies);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -7,15 +7,12 @@
|
|||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations';
|
||||
import { getMonitorsByLocation } from './get_location_monitors';
|
||||
import { getPrivateLocationsAndAgentPolicies } from './get_private_locations';
|
||||
import { SyntheticsRestApiRouteFactory } from '../../types';
|
||||
import { SYNTHETICS_API_URLS } from '../../../../common/constants';
|
||||
import {
|
||||
privateLocationsSavedObjectId,
|
||||
privateLocationsSavedObjectName,
|
||||
} from '../../../../common/saved_objects/private_locations';
|
||||
import type { SyntheticsPrivateLocationsAttributes } from '../../../runtime_types/private_locations';
|
||||
import { privateLocationSavedObjectName } from '../../../../common/saved_objects/private_locations';
|
||||
|
||||
export const deletePrivateLocationRoute: SyntheticsRestApiRouteFactory<undefined> = () => ({
|
||||
method: 'DELETE',
|
||||
|
@ -28,12 +25,16 @@ export const deletePrivateLocationRoute: SyntheticsRestApiRouteFactory<undefined
|
|||
}),
|
||||
},
|
||||
},
|
||||
handler: async ({ response, savedObjectsClient, syntheticsMonitorClient, request, server }) => {
|
||||
handler: async (routeContext) => {
|
||||
await migrateLegacyPrivateLocations(routeContext);
|
||||
|
||||
const { savedObjectsClient, syntheticsMonitorClient, request, response, server } = routeContext;
|
||||
const { locationId } = request.params as { locationId: string };
|
||||
|
||||
const { locations } = await getPrivateLocationsAndAgentPolicies(
|
||||
savedObjectsClient,
|
||||
syntheticsMonitorClient
|
||||
syntheticsMonitorClient,
|
||||
true
|
||||
);
|
||||
|
||||
if (!locations.find((loc) => loc.id === locationId)) {
|
||||
|
@ -55,17 +56,8 @@ export const deletePrivateLocationRoute: SyntheticsRestApiRouteFactory<undefined
|
|||
});
|
||||
}
|
||||
|
||||
const remainingLocations = locations.filter((loc) => loc.id !== locationId);
|
||||
|
||||
await savedObjectsClient.create<SyntheticsPrivateLocationsAttributes>(
|
||||
privateLocationsSavedObjectName,
|
||||
{ locations: remainingLocations },
|
||||
{
|
||||
id: privateLocationsSavedObjectId,
|
||||
overwrite: true,
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
await savedObjectsClient.delete(privateLocationSavedObjectName, locationId, {
|
||||
force: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { SavedObjectsErrorHelpers } from '@kbn/core/server';
|
||||
import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations';
|
||||
import { AgentPolicyInfo } from '../../../../common/types';
|
||||
import { SyntheticsRestApiRouteFactory } from '../../types';
|
||||
import { PrivateLocation, SyntheticsPrivateLocations } from '../../../../common/runtime_types';
|
||||
|
@ -14,7 +15,7 @@ import { SYNTHETICS_API_URLS } from '../../../../common/constants';
|
|||
import { getPrivateLocations } from '../../../synthetics_service/get_private_locations';
|
||||
import type { SyntheticsPrivateLocationsAttributes } from '../../../runtime_types/private_locations';
|
||||
import { SyntheticsMonitorClient } from '../../../synthetics_service/synthetics_monitor/synthetics_monitor_client';
|
||||
import { toClientContract } from './helpers';
|
||||
import { allLocationsToClientContract } from './helpers';
|
||||
|
||||
export const getPrivateLocationsRoute: SyntheticsRestApiRouteFactory<
|
||||
SyntheticsPrivateLocations | PrivateLocation
|
||||
|
@ -29,14 +30,17 @@ export const getPrivateLocationsRoute: SyntheticsRestApiRouteFactory<
|
|||
}),
|
||||
},
|
||||
},
|
||||
handler: async ({ savedObjectsClient, syntheticsMonitorClient, request, response }) => {
|
||||
handler: async (routeContext) => {
|
||||
await migrateLegacyPrivateLocations(routeContext);
|
||||
|
||||
const { savedObjectsClient, syntheticsMonitorClient, request, response } = routeContext;
|
||||
const { id } = request.params as { id?: string };
|
||||
|
||||
const { locations, agentPolicies } = await getPrivateLocationsAndAgentPolicies(
|
||||
savedObjectsClient,
|
||||
syntheticsMonitorClient
|
||||
);
|
||||
const list = toClientContract({ locations }, agentPolicies);
|
||||
const list = allLocationsToClientContract({ locations }, agentPolicies);
|
||||
if (!id) return list;
|
||||
const location = list.find((loc) => loc.id === id || loc.label === id);
|
||||
if (!location) {
|
||||
|
@ -53,7 +57,7 @@ export const getPrivateLocationsRoute: SyntheticsRestApiRouteFactory<
|
|||
export const getPrivateLocationsAndAgentPolicies = async (
|
||||
savedObjectsClient: SavedObjectsClientContract,
|
||||
syntheticsMonitorClient: SyntheticsMonitorClient,
|
||||
excludeAgentPolicies: boolean = false
|
||||
excludeAgentPolicies = false
|
||||
): Promise<SyntheticsPrivateLocationsAttributes & { agentPolicies: AgentPolicyInfo[] }> => {
|
||||
try {
|
||||
const [privateLocations, agentPolicies] = await Promise.all([
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { toClientContract } from './helpers';
|
||||
import { allLocationsToClientContract } from './helpers';
|
||||
|
||||
const testLocations = {
|
||||
locations: [
|
||||
|
@ -56,7 +56,7 @@ const testLocations2 = {
|
|||
describe('toClientContract', () => {
|
||||
it('formats SO attributes to client contract with falsy geo location', () => {
|
||||
// @ts-ignore fixtures are purposely wrong types for testing
|
||||
expect(toClientContract(testLocations)).toEqual([
|
||||
expect(allLocationsToClientContract(testLocations)).toEqual([
|
||||
{
|
||||
agentPolicyId: 'e3134290-0f73-11ee-ba15-159f4f728deb',
|
||||
geo: {
|
||||
|
@ -86,7 +86,7 @@ describe('toClientContract', () => {
|
|||
|
||||
it('formats SO attributes to client contract with truthy geo location', () => {
|
||||
// @ts-ignore fixtures are purposely wrong types for testing
|
||||
expect(toClientContract(testLocations2)).toEqual([
|
||||
expect(allLocationsToClientContract(testLocations2)).toEqual([
|
||||
{
|
||||
agentPolicyId: 'e3134290-0f73-11ee-ba15-159f4f728deb',
|
||||
geo: {
|
||||
|
|
|
@ -13,6 +13,22 @@ import type {
|
|||
import { PrivateLocation } from '../../../../common/runtime_types';
|
||||
|
||||
export const toClientContract = (
|
||||
location: PrivateLocationAttributes,
|
||||
agentPolicies?: AgentPolicyInfo[]
|
||||
): PrivateLocation => {
|
||||
const agPolicy = agentPolicies?.find((policy) => policy.id === location.agentPolicyId);
|
||||
return {
|
||||
label: location.label,
|
||||
id: location.id,
|
||||
agentPolicyId: location.agentPolicyId,
|
||||
isServiceManaged: false,
|
||||
isInvalid: !Boolean(agPolicy),
|
||||
tags: location.tags,
|
||||
geo: location.geo,
|
||||
};
|
||||
};
|
||||
|
||||
export const allLocationsToClientContract = (
|
||||
attributes: SyntheticsPrivateLocationsAttributes,
|
||||
agentPolicies?: AgentPolicyInfo[]
|
||||
): SyntheticsPrivateLocations => {
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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 { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations';
|
||||
import { SyntheticsServerSetup } from '../../../types';
|
||||
import { coreMock, savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
import { loggerMock } from '@kbn/logging-mocks';
|
||||
import {
|
||||
type ISavedObjectsRepository,
|
||||
SavedObjectsClientContract,
|
||||
} from '@kbn/core-saved-objects-api-server';
|
||||
|
||||
describe('migrateLegacyPrivateLocations', () => {
|
||||
let serverMock: SyntheticsServerSetup;
|
||||
let savedObjectsClient: jest.Mocked<SavedObjectsClientContract>;
|
||||
let repositoryMock: ISavedObjectsRepository;
|
||||
beforeEach(() => {
|
||||
const coreStartMock = coreMock.createStart();
|
||||
serverMock = {
|
||||
coreStart: coreStartMock,
|
||||
logger: loggerMock.create(),
|
||||
} as any;
|
||||
savedObjectsClient = savedObjectsClientMock.create();
|
||||
repositoryMock = coreMock.createStart().savedObjects.createInternalRepository();
|
||||
|
||||
coreStartMock.savedObjects.createInternalRepository.mockReturnValue(repositoryMock);
|
||||
});
|
||||
|
||||
it('should get the legacy private locations', async () => {
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
attributes: { locations: [{ id: '1', label: 'Location 1' }] },
|
||||
} as any);
|
||||
savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any);
|
||||
|
||||
await migrateLegacyPrivateLocations({
|
||||
server: serverMock,
|
||||
savedObjectsClient,
|
||||
} as any);
|
||||
|
||||
expect(savedObjectsClient.get).toHaveBeenCalledWith(
|
||||
'synthetics-privates-locations',
|
||||
'synthetics-privates-locations-singleton'
|
||||
);
|
||||
});
|
||||
|
||||
it('should log and return if an error occurs while getting legacy private locations', async () => {
|
||||
const error = new Error('Get error');
|
||||
savedObjectsClient.get.mockRejectedValueOnce(error);
|
||||
|
||||
await migrateLegacyPrivateLocations({
|
||||
server: serverMock,
|
||||
savedObjectsClient,
|
||||
} as any);
|
||||
|
||||
expect(serverMock.logger.error).toHaveBeenCalledWith(
|
||||
`Error getting legacy private locations: ${error}`
|
||||
);
|
||||
expect(repositoryMock.bulkCreate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return if there are no legacy locations', async () => {
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
attributes: { locations: [] },
|
||||
} as any);
|
||||
|
||||
await migrateLegacyPrivateLocations({
|
||||
server: serverMock,
|
||||
savedObjectsClient: savedObjectsClientMock,
|
||||
} as any);
|
||||
|
||||
expect(repositoryMock.bulkCreate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should bulk create new private locations if there are legacy locations', async () => {
|
||||
const legacyLocations = [{ id: '1', label: 'Location 1' }];
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
attributes: { locations: legacyLocations },
|
||||
} as any);
|
||||
savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any);
|
||||
|
||||
await migrateLegacyPrivateLocations({
|
||||
server: serverMock,
|
||||
savedObjectsClient,
|
||||
} as any);
|
||||
|
||||
expect(repositoryMock.bulkCreate).toHaveBeenCalledWith(
|
||||
legacyLocations.map((location) => ({
|
||||
id: location.id,
|
||||
attributes: location,
|
||||
type: 'synthetics-private-location',
|
||||
initialNamespaces: ['*'],
|
||||
})),
|
||||
{ overwrite: true }
|
||||
);
|
||||
});
|
||||
|
||||
it('should delete legacy private locations if bulk create count matches', async () => {
|
||||
const legacyLocations = [{ id: '1', label: 'Location 1' }];
|
||||
savedObjectsClient.get.mockResolvedValueOnce({
|
||||
attributes: { locations: legacyLocations },
|
||||
} as any);
|
||||
savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any);
|
||||
|
||||
await migrateLegacyPrivateLocations({
|
||||
server: serverMock,
|
||||
savedObjectsClient,
|
||||
} as any);
|
||||
|
||||
expect(savedObjectsClient.delete).toHaveBeenCalledWith(
|
||||
'synthetics-privates-locations',
|
||||
'synthetics-privates-locations-singleton',
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 { SavedObject } from '@kbn/core-saved-objects-server';
|
||||
import {
|
||||
type PrivateLocationAttributes,
|
||||
SyntheticsPrivateLocationsAttributes,
|
||||
} from '../../../runtime_types/private_locations';
|
||||
import {
|
||||
legacyPrivateLocationsSavedObjectId,
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
privateLocationSavedObjectName,
|
||||
} from '../../../../common/saved_objects/private_locations';
|
||||
import { RouteContext } from '../../types';
|
||||
|
||||
export const migrateLegacyPrivateLocations = async ({
|
||||
server,
|
||||
savedObjectsClient,
|
||||
}: RouteContext) => {
|
||||
try {
|
||||
let obj: SavedObject<SyntheticsPrivateLocationsAttributes> | undefined;
|
||||
try {
|
||||
obj = await savedObjectsClient.get<SyntheticsPrivateLocationsAttributes>(
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
legacyPrivateLocationsSavedObjectId
|
||||
);
|
||||
} catch (e) {
|
||||
server.logger.error(`Error getting legacy private locations: ${e}`);
|
||||
return;
|
||||
}
|
||||
const legacyLocations = obj?.attributes.locations ?? [];
|
||||
if (legacyLocations.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const soClient = server.coreStart.savedObjects.createInternalRepository();
|
||||
|
||||
await soClient.bulkCreate<PrivateLocationAttributes>(
|
||||
legacyLocations.map((location) => ({
|
||||
id: location.id,
|
||||
attributes: location,
|
||||
type: privateLocationSavedObjectName,
|
||||
initialNamespaces: ['*'],
|
||||
})),
|
||||
{
|
||||
overwrite: true,
|
||||
}
|
||||
);
|
||||
|
||||
const { total } = await savedObjectsClient.find<PrivateLocationAttributes>({
|
||||
type: privateLocationSavedObjectName,
|
||||
fields: [],
|
||||
perPage: 0,
|
||||
});
|
||||
|
||||
if (total === legacyLocations.length) {
|
||||
await savedObjectsClient.delete(
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
legacyPrivateLocationsSavedObjectId,
|
||||
{}
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
server.logger.error(`Error migrating legacy private locations: ${e}`);
|
||||
}
|
||||
};
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { toClientContract } from '../settings/private_locations/helpers';
|
||||
import { allLocationsToClientContract } from '../settings/private_locations/helpers';
|
||||
import { getPrivateLocationsAndAgentPolicies } from '../settings/private_locations/get_private_locations';
|
||||
import { SyntheticsRestApiRouteFactory } from '../types';
|
||||
import { getAllLocations } from '../../synthetics_service/get_all_locations';
|
||||
|
@ -45,7 +45,7 @@ export const getServiceLocationsRoute: SyntheticsRestApiRouteFactory = () => ({
|
|||
const { locations: privateLocations, agentPolicies } =
|
||||
await getPrivateLocationsAndAgentPolicies(savedObjectsClient, syntheticsMonitorClient);
|
||||
|
||||
const result = toClientContract({ locations: privateLocations }, agentPolicies);
|
||||
const result = allLocationsToClientContract({ locations: privateLocations }, agentPolicies);
|
||||
return {
|
||||
locations: result,
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { transformGeoProperty } from './model_version_1';
|
||||
import { privateLocationsSavedObjectName } from '../../../../common/saved_objects/private_locations';
|
||||
import { legacyPrivateLocationsSavedObjectName } from '../../../../common/saved_objects/private_locations';
|
||||
|
||||
describe('model version 1 migration', () => {
|
||||
const testLocation = {
|
||||
|
@ -19,7 +19,7 @@ describe('model version 1 migration', () => {
|
|||
concurrentMonitors: 1,
|
||||
};
|
||||
const testObject = {
|
||||
type: privateLocationsSavedObjectName,
|
||||
type: legacyPrivateLocationsSavedObjectName,
|
||||
id: 'synthetics-privates-locations-singleton',
|
||||
attributes: {
|
||||
locations: [testLocation],
|
||||
|
|
|
@ -7,11 +7,33 @@
|
|||
|
||||
import { SavedObjectsType } from '@kbn/core/server';
|
||||
import { modelVersion1 } from './migrations/private_locations/model_version_1';
|
||||
import { privateLocationsSavedObjectName } from '../../common/saved_objects/private_locations';
|
||||
export const privateLocationsSavedObjectId = 'synthetics-privates-locations-singleton';
|
||||
import {
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
privateLocationSavedObjectName,
|
||||
} from '../../common/saved_objects/private_locations';
|
||||
|
||||
export const PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE: SavedObjectsType = {
|
||||
name: privateLocationsSavedObjectName,
|
||||
export const PRIVATE_LOCATION_SAVED_OBJECT_TYPE: SavedObjectsType = {
|
||||
name: privateLocationSavedObjectName,
|
||||
hidden: false,
|
||||
namespaceType: 'multiple',
|
||||
mappings: {
|
||||
dynamic: false,
|
||||
properties: {
|
||||
/* Leaving these commented to make it clear that these fields exist, even though we don't want them indexed.
|
||||
When adding new fields please add them here. If they need to be searchable put them in the uncommented
|
||||
part of properties.
|
||||
*/
|
||||
},
|
||||
},
|
||||
management: {
|
||||
importableAndExportable: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const legacyPrivateLocationsSavedObjectId = 'synthetics-privates-locations-singleton';
|
||||
|
||||
export const LEGACY_PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE: SavedObjectsType = {
|
||||
name: legacyPrivateLocationsSavedObjectName,
|
||||
hidden: false,
|
||||
namespaceType: 'agnostic',
|
||||
mappings: {
|
||||
|
|
|
@ -24,7 +24,10 @@ import {
|
|||
SYNTHETICS_SECRET_ENCRYPTED_TYPE,
|
||||
syntheticsParamSavedObjectType,
|
||||
} from './synthetics_param';
|
||||
import { PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE } from './private_locations';
|
||||
import {
|
||||
LEGACY_PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE,
|
||||
PRIVATE_LOCATION_SAVED_OBJECT_TYPE,
|
||||
} from './private_locations';
|
||||
import { DYNAMIC_SETTINGS_DEFAULT_ATTRIBUTES } from '../constants/settings';
|
||||
import { DynamicSettingsAttributes } from '../runtime_types/settings';
|
||||
import {
|
||||
|
@ -37,7 +40,8 @@ export const registerSyntheticsSavedObjects = (
|
|||
savedObjectsService: SavedObjectsServiceSetup,
|
||||
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup
|
||||
) => {
|
||||
savedObjectsService.registerType(PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE);
|
||||
savedObjectsService.registerType(LEGACY_PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE);
|
||||
savedObjectsService.registerType(PRIVATE_LOCATION_SAVED_OBJECT_TYPE);
|
||||
|
||||
savedObjectsService.registerType(getSyntheticsMonitorSavedObjectType(encryptedSavedObjects));
|
||||
savedObjectsService.registerType(syntheticsServiceApiKey);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { toClientContract } from '../routes/settings/private_locations/helpers';
|
||||
import { allLocationsToClientContract } from '../routes/settings/private_locations/helpers';
|
||||
import { getPrivateLocationsAndAgentPolicies } from '../routes/settings/private_locations/get_private_locations';
|
||||
import { SyntheticsServerSetup } from '../types';
|
||||
import { getServiceLocations } from './get_service_locations';
|
||||
|
@ -34,7 +34,10 @@ export async function getAllLocations({
|
|||
),
|
||||
getServicePublicLocations(server, syntheticsMonitorClient),
|
||||
]);
|
||||
const pvtLocations = toClientContract({ locations: privateLocations }, agentPolicies);
|
||||
const pvtLocations = allLocationsToClientContract(
|
||||
{ locations: privateLocations },
|
||||
agentPolicies
|
||||
);
|
||||
return {
|
||||
publicLocations,
|
||||
privateLocations: pvtLocations,
|
||||
|
|
|
@ -5,22 +5,42 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SavedObjectsClientContract, SavedObjectsErrorHelpers } from '@kbn/core/server';
|
||||
import {
|
||||
privateLocationsSavedObjectId,
|
||||
privateLocationsSavedObjectName,
|
||||
SavedObject,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsErrorHelpers,
|
||||
} from '@kbn/core/server';
|
||||
import { uniqBy } from 'lodash';
|
||||
import {
|
||||
legacyPrivateLocationsSavedObjectId,
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
privateLocationSavedObjectName,
|
||||
} from '../../common/saved_objects/private_locations';
|
||||
import type { SyntheticsPrivateLocationsAttributes } from '../runtime_types/private_locations';
|
||||
import {
|
||||
PrivateLocationAttributes,
|
||||
SyntheticsPrivateLocationsAttributes,
|
||||
} from '../runtime_types/private_locations';
|
||||
|
||||
export const getPrivateLocations = async (
|
||||
client: SavedObjectsClientContract
|
||||
): Promise<SyntheticsPrivateLocationsAttributes['locations']> => {
|
||||
try {
|
||||
const obj = await client.get<SyntheticsPrivateLocationsAttributes>(
|
||||
privateLocationsSavedObjectName,
|
||||
privateLocationsSavedObjectId
|
||||
);
|
||||
return obj?.attributes.locations ?? [];
|
||||
const finder = client.createPointInTimeFinder<PrivateLocationAttributes>({
|
||||
type: privateLocationSavedObjectName,
|
||||
perPage: 1000,
|
||||
});
|
||||
|
||||
const results: Array<SavedObject<PrivateLocationAttributes>> = [];
|
||||
|
||||
for await (const response of finder.find()) {
|
||||
results.push(...response.saved_objects);
|
||||
}
|
||||
|
||||
finder.close().catch((e) => {});
|
||||
|
||||
const legacyLocations = await getLegacyPrivateLocations(client);
|
||||
|
||||
return uniqBy([...results.map((r) => r.attributes), ...legacyLocations], 'id');
|
||||
} catch (getErr) {
|
||||
if (SavedObjectsErrorHelpers.isNotFoundError(getErr)) {
|
||||
return [];
|
||||
|
@ -28,3 +48,15 @@ export const getPrivateLocations = async (
|
|||
throw getErr;
|
||||
}
|
||||
};
|
||||
|
||||
const getLegacyPrivateLocations = async (client: SavedObjectsClientContract) => {
|
||||
try {
|
||||
const obj = await client.get<SyntheticsPrivateLocationsAttributes>(
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
legacyPrivateLocationsSavedObjectId
|
||||
);
|
||||
return obj?.attributes.locations ?? [];
|
||||
} catch (getErr) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* 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 { v4 as uuidv4 } from 'uuid';
|
||||
import { privateLocationsSavedObjectName } from '@kbn/synthetics-plugin/common/saved_objects/private_locations';
|
||||
import { privateLocationsSavedObjectId } from '@kbn/synthetics-plugin/server/saved_objects/private_locations';
|
||||
import { SyntheticsPrivateLocations } from '@kbn/synthetics-plugin/common/runtime_types';
|
||||
import { Agent as SuperTestAgent } from 'supertest';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
|
||||
export const INSTALLED_VERSION = '1.1.1';
|
||||
|
||||
export class PrivateLocationTestService {
|
||||
private supertest: SuperTestAgent;
|
||||
private readonly getService: FtrProviderContext['getService'];
|
||||
|
||||
constructor(getService: FtrProviderContext['getService']) {
|
||||
this.supertest = getService('supertest');
|
||||
this.getService = getService;
|
||||
}
|
||||
|
||||
async installSyntheticsPackage() {
|
||||
await this.supertest.post('/api/fleet/setup').set('kbn-xsrf', 'true').send().expect(200);
|
||||
const response = await this.supertest
|
||||
.get(`/api/fleet/epm/packages/synthetics/${INSTALLED_VERSION}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
if (response.body.item.status !== 'installed') {
|
||||
await this.supertest
|
||||
.post(`/api/fleet/epm/packages/synthetics/${INSTALLED_VERSION}`)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({ force: true })
|
||||
.expect(200);
|
||||
}
|
||||
}
|
||||
|
||||
async addTestPrivateLocation() {
|
||||
const apiResponse = await this.addFleetPolicy(uuidv4());
|
||||
const testPolicyId = apiResponse.body.item.id;
|
||||
return (await this.setTestLocations([testPolicyId]))[0];
|
||||
}
|
||||
|
||||
async addFleetPolicy(name: string) {
|
||||
return this.supertest
|
||||
.post('/api/fleet/agent_policies?sys_monitoring=true')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
name,
|
||||
description: '',
|
||||
namespace: 'default',
|
||||
monitoring_enabled: [],
|
||||
})
|
||||
.expect(200);
|
||||
}
|
||||
|
||||
async setTestLocations(testFleetPolicyIds: string[]) {
|
||||
const server = this.getService('kibanaServer');
|
||||
|
||||
const locations: SyntheticsPrivateLocations = testFleetPolicyIds.map((id, index) => ({
|
||||
label: 'Test private location ' + index,
|
||||
agentPolicyId: id,
|
||||
id,
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
isServiceManaged: false,
|
||||
}));
|
||||
|
||||
await server.savedObjects.create({
|
||||
type: privateLocationsSavedObjectName,
|
||||
id: privateLocationsSavedObjectId,
|
||||
attributes: {
|
||||
locations,
|
||||
},
|
||||
overwrite: true,
|
||||
});
|
||||
return locations;
|
||||
}
|
||||
}
|
|
@ -16,9 +16,9 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
|
|||
import { Agent as SuperTestAgent } from 'supertest';
|
||||
import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants';
|
||||
import expect from '@kbn/expect';
|
||||
import { PrivateLocationTestService } from '../../../api_integration/apis/synthetics/services/private_location_test_service';
|
||||
import { waitForAlertInIndex } from '../helpers/alerting_wait_for_helpers';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import { PrivateLocationTestService } from './private_location_test_service';
|
||||
import { createIndexConnector, createRule } from '../helpers/alerting_api_helper';
|
||||
|
||||
export const SYNTHETICS_ALERT_ACTION_INDEX = 'alert-action-synthetics';
|
||||
|
@ -172,11 +172,6 @@ export class SyntheticsRuleHelper {
|
|||
return result.body as EncryptedSyntheticsSavedMonitor;
|
||||
}
|
||||
|
||||
async addPrivateLocation() {
|
||||
await this.locService.installSyntheticsPackage();
|
||||
return this.locService.addTestPrivateLocation();
|
||||
}
|
||||
|
||||
async waitForStatusAlert({
|
||||
ruleId,
|
||||
filters,
|
||||
|
|
|
@ -37,6 +37,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const supertestWithoutAuth = getService('supertestWithoutAuth');
|
||||
|
||||
let testFleetPolicyID: string;
|
||||
let pvtLoc: PrivateLocation;
|
||||
const testPolicyName = 'Fleet test server policy' + Date.now();
|
||||
|
||||
let _httpMonitorJson: HTTPFields;
|
||||
|
@ -68,29 +69,15 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
httpMonitorJson = _httpMonitorJson;
|
||||
});
|
||||
|
||||
it('adds a test fleet policy', async () => {
|
||||
const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName);
|
||||
testFleetPolicyID = apiResponse.body.item.id;
|
||||
});
|
||||
|
||||
it('add a test private location', async () => {
|
||||
await testPrivateLocations.setTestLocations([testFleetPolicyID]);
|
||||
pvtLoc = await testPrivateLocations.addPrivateLocation();
|
||||
testFleetPolicyID = pvtLoc.id;
|
||||
|
||||
const apiResponse = await supertestAPI.get(SYNTHETICS_API_URLS.SERVICE_LOCATIONS);
|
||||
|
||||
const testResponse: Array<PrivateLocation | ServiceLocation> = [
|
||||
...getDevLocation('mockDevUrl'),
|
||||
{
|
||||
id: testFleetPolicyID,
|
||||
isServiceManaged: false,
|
||||
isInvalid: false,
|
||||
label: 'Test private location 0',
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
agentPolicyId: testFleetPolicyID,
|
||||
},
|
||||
{ ...pvtLoc, isInvalid: false },
|
||||
];
|
||||
|
||||
expect(apiResponse.body.locations).eql(testResponse);
|
||||
|
@ -137,16 +124,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
it('adds a monitor in private location', async () => {
|
||||
const newMonitor = httpMonitorJson;
|
||||
|
||||
newMonitor.locations.push({
|
||||
id: testFleetPolicyID,
|
||||
agentPolicyId: testFleetPolicyID,
|
||||
label: 'Test private location 0',
|
||||
isServiceManaged: false,
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
});
|
||||
newMonitor.locations.push(pvtLoc);
|
||||
|
||||
const { body, rawBody } = await addMonitorAPI(newMonitor);
|
||||
|
||||
|
@ -182,19 +160,13 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const resPolicy = await testPrivateLocations.addFleetPolicy(testPolicyName + 1);
|
||||
testFleetPolicyID2 = resPolicy.body.item.id;
|
||||
|
||||
await testPrivateLocations.setTestLocations([testFleetPolicyID, testFleetPolicyID2]);
|
||||
|
||||
httpMonitorJson.locations.push({
|
||||
id: testFleetPolicyID2,
|
||||
agentPolicyId: testFleetPolicyID2,
|
||||
label: 'Test private location ' + 1,
|
||||
isServiceManaged: false,
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
const pvtLoc2 = await testPrivateLocations.addPrivateLocation({
|
||||
policyId: testFleetPolicyID2,
|
||||
label: 'Test private location 1',
|
||||
});
|
||||
|
||||
httpMonitorJson.locations.push(pvtLoc2);
|
||||
|
||||
const apiResponse = await supertestAPI
|
||||
.put(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS + '/' + newMonitorId)
|
||||
.set('kbn-xsrf', 'true')
|
||||
|
@ -308,54 +280,23 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('handles spaces', async () => {
|
||||
const username = 'admin';
|
||||
const password = `${username}-password`;
|
||||
const roleName = 'uptime-role';
|
||||
const SPACE_ID = `test-space-${uuidv4()}`;
|
||||
const SPACE_NAME = `test-space-name ${uuidv4()}`;
|
||||
const { username, password, SPACE_ID, roleName } = await monitorTestService.addsNewSpace();
|
||||
|
||||
let monitorId = '';
|
||||
const monitor = {
|
||||
...httpMonitorJson,
|
||||
name: `Test monitor ${uuidv4()}`,
|
||||
[ConfigKey.NAMESPACE]: 'default',
|
||||
locations: [
|
||||
{
|
||||
id: testFleetPolicyID,
|
||||
agentPolicyId: testFleetPolicyID,
|
||||
label: 'Test private location 0',
|
||||
isServiceManaged: false,
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
locations: [pvtLoc],
|
||||
};
|
||||
|
||||
try {
|
||||
await kibanaServer.spaces.create({ id: SPACE_ID, name: SPACE_NAME });
|
||||
await security.role.create(roleName, {
|
||||
kibana: [
|
||||
{
|
||||
feature: {
|
||||
uptime: ['all'],
|
||||
actions: ['all'],
|
||||
},
|
||||
spaces: ['*'],
|
||||
},
|
||||
],
|
||||
});
|
||||
await security.user.create(username, {
|
||||
password,
|
||||
roles: [roleName],
|
||||
full_name: 'a kibana user',
|
||||
});
|
||||
const apiResponse = await supertestWithoutAuth
|
||||
.post(`/s/${SPACE_ID}${SYNTHETICS_API_URLS.SYNTHETICS_MONITORS}`)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(monitor)
|
||||
.expect(200);
|
||||
.send(monitor);
|
||||
expect(apiResponse.status).eql(200, JSON.stringify(apiResponse.body));
|
||||
|
||||
const { created_at: createdAt, updated_at: updatedAt } = apiResponse.body;
|
||||
expect([createdAt, updatedAt].map((d) => moment(d).isValid())).eql([true, true]);
|
||||
|
|
|
@ -46,8 +46,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
let icmpProjectMonitors: ProjectMonitorsRequest;
|
||||
|
||||
let testPolicyId = '';
|
||||
const testPolicyName = 'Fleet test server policy' + Date.now();
|
||||
|
||||
const setUniqueIds = (request: ProjectMonitorsRequest) => {
|
||||
return {
|
||||
...request,
|
||||
|
@ -87,9 +85,8 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
.expect(200);
|
||||
await testPrivateLocations.installSyntheticsPackage();
|
||||
|
||||
const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName);
|
||||
testPolicyId = apiResponse.body.item.id;
|
||||
await testPrivateLocations.setTestLocations([testPolicyId]);
|
||||
const loc = await testPrivateLocations.addPrivateLocation();
|
||||
testPolicyId = loc.id;
|
||||
await supertest
|
||||
.post(SYNTHETICS_API_URLS.PARAMS)
|
||||
.set('kbn-xsrf', 'true')
|
||||
|
|
|
@ -24,9 +24,6 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
let projectMonitors: ProjectMonitorsRequest;
|
||||
|
||||
const monitorTestService = new SyntheticsMonitorTestService(getService);
|
||||
|
||||
let testPolicyId = '';
|
||||
const testPolicyName = 'Fleet test server policy' + Date.now();
|
||||
const testPrivateLocations = new PrivateLocationTestService(getService);
|
||||
|
||||
const setUniqueIds = (request: ProjectMonitorsRequest) => {
|
||||
|
@ -42,10 +39,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
await testPrivateLocations.installSyntheticsPackage();
|
||||
|
||||
const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName);
|
||||
testPolicyId = apiResponse.body.item.id;
|
||||
await testPrivateLocations.setTestLocations([testPolicyId]);
|
||||
await testPrivateLocations.addPrivateLocation();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
|
|
|
@ -59,10 +59,8 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
await testPrivateLocations.installSyntheticsPackage();
|
||||
|
||||
const testPolicyName = 'Fleet test server policy' + Date.now();
|
||||
const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName);
|
||||
testPolicyId = apiResponse.body.item.id;
|
||||
await testPrivateLocations.setTestLocations([testPolicyId]);
|
||||
const loc = await testPrivateLocations.addPrivateLocation();
|
||||
testPolicyId = loc.id;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -37,11 +37,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
};
|
||||
|
||||
before(async () => {
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
await testPrivateLocations.installSyntheticsPackage();
|
||||
const testPolicyName = 'Fleet test server policy' + Date.now();
|
||||
const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName);
|
||||
testPolicyId = apiResponse.body.item.id;
|
||||
await testPrivateLocations.setTestLocations([testPolicyId]);
|
||||
const loc = await testPrivateLocations.addPrivateLocation();
|
||||
testPolicyId = loc.id;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -79,10 +79,8 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
|
||||
const testPolicyName = 'Fleet test server policy' + Date.now();
|
||||
const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName);
|
||||
testPolicyId = apiResponse.body.item.id;
|
||||
await testPrivateLocations.setTestLocations([testPolicyId]);
|
||||
const loc = await testPrivateLocations.addPrivateLocation();
|
||||
testPolicyId = loc.id;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
|
|
|
@ -240,7 +240,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
it('can add private location to existing monitor', async () => {
|
||||
await testPrivateLocations.installSyntheticsPackage();
|
||||
pvtLoc = await testPrivateLocations.addTestPrivateLocation();
|
||||
pvtLoc = await testPrivateLocations.addPrivateLocation();
|
||||
|
||||
expect(pvtLoc).not.empty();
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
this.tags('skipCloud');
|
||||
|
||||
const supertest = getService('supertest');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
||||
let projectMonitors: LegacyProjectMonitorsRequest;
|
||||
let httpProjectMonitors: LegacyProjectMonitorsRequest;
|
||||
let tcpProjectMonitors: LegacyProjectMonitorsRequest;
|
||||
let icmpProjectMonitors: LegacyProjectMonitorsRequest;
|
||||
|
||||
let testPolicyId = '';
|
||||
const testPrivateLocations = new PrivateLocationTestService(getService);
|
||||
|
||||
const setUniqueIds = (request: LegacyProjectMonitorsRequest) => {
|
||||
|
@ -39,12 +39,10 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
};
|
||||
|
||||
before(async () => {
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
await testPrivateLocations.installSyntheticsPackage();
|
||||
|
||||
const testPolicyName = 'Fleet test server policy' + Date.now();
|
||||
const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName);
|
||||
testPolicyId = apiResponse.body.item.id;
|
||||
await testPrivateLocations.setTestLocations([testPolicyId]);
|
||||
await testPrivateLocations.addPrivateLocation();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -35,5 +35,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./inspect_monitor'));
|
||||
loadTestFile(require.resolve('./test_now_monitor'));
|
||||
loadTestFile(require.resolve('./suggestions'));
|
||||
loadTestFile(require.resolve('./private_location_apis'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('inspect http monitor in private location', async () => {
|
||||
const location = await testPrivateLocations.addTestPrivateLocation();
|
||||
const location = await testPrivateLocations.addPrivateLocation();
|
||||
const apiResponse = await monitorTestService.inspectMonitor({
|
||||
..._monitors[0],
|
||||
locations: [
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import {
|
||||
legacyPrivateLocationsSavedObjectId,
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
privateLocationSavedObjectName,
|
||||
} from '@kbn/synthetics-plugin/common/saved_objects/private_locations';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { PrivateLocationTestService } from './services/private_location_test_service';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
describe('PrivateLocationAPI', function () {
|
||||
this.tags('skipCloud');
|
||||
|
||||
const kServer = getService('kibanaServer');
|
||||
|
||||
const testPrivateLocations = new PrivateLocationTestService(getService);
|
||||
|
||||
before(async () => {
|
||||
await testPrivateLocations.installSyntheticsPackage();
|
||||
|
||||
await kServer.savedObjects.clean({
|
||||
types: [legacyPrivateLocationsSavedObjectName, privateLocationSavedObjectName],
|
||||
});
|
||||
});
|
||||
|
||||
it('adds a test legacy private location', async () => {
|
||||
const locs = await testPrivateLocations.addLegacyPrivateLocations();
|
||||
expect(locs.length).to.be(2);
|
||||
});
|
||||
|
||||
it('adds a test private location', async () => {
|
||||
await testPrivateLocations.addPrivateLocation();
|
||||
});
|
||||
|
||||
it('list all locations', async () => {
|
||||
const locs = await testPrivateLocations.fetchAll();
|
||||
expect(locs.body.length).to.be(3);
|
||||
});
|
||||
|
||||
it('migrates to new saved objet type', async () => {
|
||||
const newData = await kServer.savedObjects.find({
|
||||
type: privateLocationSavedObjectName,
|
||||
});
|
||||
|
||||
expect(newData.saved_objects.length).to.be(3);
|
||||
|
||||
try {
|
||||
await kServer.savedObjects.get({
|
||||
type: legacyPrivateLocationsSavedObjectName,
|
||||
id: legacyPrivateLocationsSavedObjectId,
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.response.status).to.be(404);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -4,11 +4,14 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { privateLocationsSavedObjectName } from '@kbn/synthetics-plugin/common/saved_objects/private_locations';
|
||||
import { privateLocationsSavedObjectId } from '@kbn/synthetics-plugin/server/saved_objects/private_locations';
|
||||
import { SyntheticsPrivateLocations } from '@kbn/synthetics-plugin/common/runtime_types';
|
||||
import expect from '@kbn/expect';
|
||||
import { PrivateLocation } from '@kbn/synthetics-plugin/common/runtime_types';
|
||||
import { KibanaSupertestProvider } from '@kbn/ftr-common-functional-services';
|
||||
import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants';
|
||||
import {
|
||||
legacyPrivateLocationsSavedObjectId,
|
||||
legacyPrivateLocationsSavedObjectName,
|
||||
} from '@kbn/synthetics-plugin/common/saved_objects/private_locations';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export const INSTALLED_VERSION = '1.1.1';
|
||||
|
@ -37,18 +40,12 @@ export class PrivateLocationTestService {
|
|||
}
|
||||
}
|
||||
|
||||
async addTestPrivateLocation() {
|
||||
const apiResponse = await this.addFleetPolicy(uuidv4());
|
||||
const testPolicyId = apiResponse.body.item.id;
|
||||
return (await this.setTestLocations([testPolicyId]))[0];
|
||||
}
|
||||
|
||||
async addFleetPolicy(name: string) {
|
||||
async addFleetPolicy(name?: string) {
|
||||
return this.supertest
|
||||
.post('/api/fleet/agent_policies?sys_monitoring=true')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send({
|
||||
name,
|
||||
name: name ?? 'Fleet test server policy' + Date.now(),
|
||||
description: '',
|
||||
namespace: 'default',
|
||||
monitoring_enabled: [],
|
||||
|
@ -56,28 +53,72 @@ export class PrivateLocationTestService {
|
|||
.expect(200);
|
||||
}
|
||||
|
||||
async setTestLocations(testFleetPolicyIds: string[]) {
|
||||
const server = this.getService('kibanaServer');
|
||||
async addPrivateLocation({ policyId, label }: { policyId?: string; label?: string } = {}) {
|
||||
let agentPolicyId = policyId;
|
||||
|
||||
const locations: SyntheticsPrivateLocations = testFleetPolicyIds.map((id, index) => ({
|
||||
label: 'Test private location ' + index,
|
||||
agentPolicyId: id,
|
||||
id,
|
||||
if (!agentPolicyId) {
|
||||
const apiResponse = await this.addFleetPolicy();
|
||||
agentPolicyId = apiResponse.body.item.id;
|
||||
}
|
||||
|
||||
const location: Omit<PrivateLocation, 'id'> = {
|
||||
label: label ?? 'Test private location 0',
|
||||
agentPolicyId: agentPolicyId!,
|
||||
geo: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
isServiceManaged: false,
|
||||
}));
|
||||
};
|
||||
|
||||
const response = await this.supertest
|
||||
.post(SYNTHETICS_API_URLS.PRIVATE_LOCATIONS)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(location);
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
|
||||
const { isInvalid, ...loc } = response.body;
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
async addLegacyPrivateLocations() {
|
||||
const server = this.getService('kibanaServer');
|
||||
const fleetPolicy = await this.addFleetPolicy();
|
||||
const fleetPolicy2 = await this.addFleetPolicy();
|
||||
|
||||
const locs = [
|
||||
{
|
||||
id: fleetPolicy.body.item.id,
|
||||
agentPolicyId: fleetPolicy.body.item.id,
|
||||
name: 'Test private location 1',
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
{
|
||||
id: fleetPolicy2.body.item.id,
|
||||
agentPolicyId: fleetPolicy2.body.item.id,
|
||||
name: 'Test private location 2',
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
];
|
||||
|
||||
await server.savedObjects.create({
|
||||
type: privateLocationsSavedObjectName,
|
||||
id: privateLocationsSavedObjectId,
|
||||
type: legacyPrivateLocationsSavedObjectName,
|
||||
id: legacyPrivateLocationsSavedObjectId,
|
||||
attributes: {
|
||||
locations,
|
||||
locations: locs,
|
||||
},
|
||||
overwrite: true,
|
||||
});
|
||||
return locations;
|
||||
return locs;
|
||||
}
|
||||
|
||||
async fetchAll() {
|
||||
return this.supertest
|
||||
.get(SYNTHETICS_API_URLS.PRIVATE_LOCATIONS)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.expect(200);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ export class SyntheticsMonitorTestService {
|
|||
full_name: 'a kibana user',
|
||||
});
|
||||
|
||||
return { username, password, SPACE_ID };
|
||||
return { username, password, SPACE_ID, roleName };
|
||||
}
|
||||
|
||||
async deleteMonitor(monitorId?: string | string[], statusCode = 200, spaceId?: string) {
|
||||
|
|
|
@ -60,15 +60,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
httpMonitorJson = _httpMonitorJson;
|
||||
});
|
||||
|
||||
const testPolicyName = 'Fleet test server policy' + Date.now();
|
||||
|
||||
it('adds a test fleet policy', async () => {
|
||||
const apiResponse = await testPrivateLocations.addFleetPolicy(testPolicyName);
|
||||
testFleetPolicyID = apiResponse.body.item.id;
|
||||
});
|
||||
|
||||
it('add a test private location', async () => {
|
||||
await testPrivateLocations.setTestLocations([testFleetPolicyID]);
|
||||
const loc = await testPrivateLocations.addPrivateLocation();
|
||||
testFleetPolicyID = loc.id;
|
||||
|
||||
const apiResponse = await supertestAPI.get(SYNTHETICS_API_URLS.SERVICE_LOCATIONS);
|
||||
|
||||
|
|
|
@ -48,6 +48,15 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
);
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
// clean up all api keys
|
||||
const { body } = await esSupertest.get(`/_security/api_key`).query({ with_limited_by: true });
|
||||
const apiKeys = body.api_keys || [];
|
||||
for (const apiKey of apiKeys) {
|
||||
await esSupertest.delete(`/_security/api_key`).send({ ids: [apiKey.id] });
|
||||
}
|
||||
});
|
||||
|
||||
describe('[PUT] /internal/uptime/service/enablement', () => {
|
||||
beforeEach(async () => {
|
||||
const apiKeys = await getApiKeys();
|
||||
|
|
|
@ -8728,6 +8728,18 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
"saved_object:uptime-synthetics-api-key/delete",
|
||||
"saved_object:uptime-synthetics-api-key/bulk_delete",
|
||||
"saved_object:uptime-synthetics-api-key/share_to_space",
|
||||
"saved_object:synthetics-private-location/bulk_get",
|
||||
"saved_object:synthetics-private-location/get",
|
||||
"saved_object:synthetics-private-location/find",
|
||||
"saved_object:synthetics-private-location/open_point_in_time",
|
||||
"saved_object:synthetics-private-location/close_point_in_time",
|
||||
"saved_object:synthetics-private-location/create",
|
||||
"saved_object:synthetics-private-location/bulk_create",
|
||||
"saved_object:synthetics-private-location/update",
|
||||
"saved_object:synthetics-private-location/bulk_update",
|
||||
"saved_object:synthetics-private-location/delete",
|
||||
"saved_object:synthetics-private-location/bulk_delete",
|
||||
"saved_object:synthetics-private-location/share_to_space",
|
||||
"saved_object:synthetics-privates-locations/bulk_get",
|
||||
"saved_object:synthetics-privates-locations/get",
|
||||
"saved_object:synthetics-privates-locations/find",
|
||||
|
@ -9417,6 +9429,18 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
"saved_object:uptime-synthetics-api-key/delete",
|
||||
"saved_object:uptime-synthetics-api-key/bulk_delete",
|
||||
"saved_object:uptime-synthetics-api-key/share_to_space",
|
||||
"saved_object:synthetics-private-location/bulk_get",
|
||||
"saved_object:synthetics-private-location/get",
|
||||
"saved_object:synthetics-private-location/find",
|
||||
"saved_object:synthetics-private-location/open_point_in_time",
|
||||
"saved_object:synthetics-private-location/close_point_in_time",
|
||||
"saved_object:synthetics-private-location/create",
|
||||
"saved_object:synthetics-private-location/bulk_create",
|
||||
"saved_object:synthetics-private-location/update",
|
||||
"saved_object:synthetics-private-location/bulk_update",
|
||||
"saved_object:synthetics-private-location/delete",
|
||||
"saved_object:synthetics-private-location/bulk_delete",
|
||||
"saved_object:synthetics-private-location/share_to_space",
|
||||
"saved_object:synthetics-privates-locations/bulk_get",
|
||||
"saved_object:synthetics-privates-locations/get",
|
||||
"saved_object:synthetics-privates-locations/find",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue