Skip to content

Commit

Permalink
Merge branch 'main' into eui/82.2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Jul 6, 2023
2 parents 781766f + b641a22 commit c3fffe3
Show file tree
Hide file tree
Showing 46 changed files with 1,142 additions and 228 deletions.
4 changes: 2 additions & 2 deletions docs/api/alerting/create_rule.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ POST api/alerting/rule
"group":"threshold met",
"params":{
"level":"info",
"message":"alert '{{alertName}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
"message":"Rule '{{rule.name}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{rule.params.timeWindowSize}}{{rule.params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
}
}
],
Expand Down Expand Up @@ -231,7 +231,7 @@ The API returns the following:
"id": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2",
"params": {
"level": "info",
"message": "alert {{alertName}} is active for group {{context.group}}:\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
"message": "Rule {{rule.name}} is active for group {{context.group}}:\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{rule.params.timeWindowSize}}{{rule.params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
},
"connector_type_id": ".server-log"
}
Expand Down
2 changes: 1 addition & 1 deletion docs/api/alerting/get_rules.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ The API returns the following:
"id":"1007a0c0-7a6e-11ed-89d5-abec321c0def",
"params":{
"level":"info",
"message":"alert {{alertName}} is active for group {{context.group}}:\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
"message":"Rule {{rule.name}} is active for group {{context.group}}:\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{rule.params.timeWindowSize}}{{rule.params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
},
"connector_type_id":".server-log"
}],
Expand Down
4 changes: 2 additions & 2 deletions docs/api/alerting/legacy/create.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ $ curl -X POST api/alerts/alert -H 'kbn-xsrf: true' -H 'Content-Type: applicati
"group":"threshold met",
"params":{
"level":"info",
"message":"alert '{{alertName}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
"message":"Rule '{{rule.name}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{rule.params.timeWindowSize}}{{rule.params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
}
}
],
Expand Down Expand Up @@ -175,7 +175,7 @@ The API returns the following:
"group": "threshold met",
"params": {
"level": "info",
"message": "alert {{alertName}} is active for group {{context.group}}:\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
"message": "Rule {{rule.name}} is active for group {{context.group}}:\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{rule.params.timeWindowSize}}{{rule.params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
},
"id": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2"
}
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/data_views/server/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ export const SPECIFIC_SCRIPTED_FIELD_PATH = `${SCRIPTED_FIELD_PATH}/{name}`;
*/
export const SPECIFIC_SCRIPTED_FIELD_PATH_LEGACY = `${SCRIPTED_FIELD_PATH_LEGACY}/{name}`;

/**
* Path to swap references
*/
export const DATA_VIEW_SWAP_REFERENCES_PATH = `${SERVICE_PATH}/swap_references`;

/**
* name of service in path form
*/
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data_views/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export {
SPECIFIC_SCRIPTED_FIELD_PATH_LEGACY,
SERVICE_KEY,
SERVICE_KEY_LEGACY,
DATA_VIEW_SWAP_REFERENCES_PATH,
} from './constants';

export type { SERVICE_KEY_TYPE } from './constants';
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/data_views/server/rest_api_routes/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import * as getRoutes from './get_data_view';
import * as getAllRoutes from './get_data_views';
import * as hasRoutes from './has_user_data_view';
import * as updateRoutes from './update_data_view';
import { swapReferencesRoute } from './swap_references';

const routes = [
fieldRoutes.registerUpdateFieldsRoute,
Expand Down Expand Up @@ -45,6 +46,7 @@ const routes = [
updateRoutes.registerUpdateDataViewRoute,
updateRoutes.registerUpdateDataViewRouteLegacy,
...Object.values(scriptedRoutes),
swapReferencesRoute,
];

export { routes };
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* 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 { UsageCounter } from '@kbn/usage-collection-plugin/server';
import { schema } from '@kbn/config-schema';
import { IRouter, StartServicesAccessor, SavedObjectsFindOptions } from '@kbn/core/server';
import { DataViewsService } from '../../../common';
import { handleErrors } from './util/handle_errors';
import type {
DataViewsServerPluginStartDependencies,
DataViewsServerPluginStart,
} from '../../types';
import { DATA_VIEW_SWAP_REFERENCES_PATH, INITIAL_REST_VERSION } from '../../constants';
import { DATA_VIEW_SAVED_OBJECT_TYPE } from '../../../common/constants';

interface GetDataViewArgs {
dataViewsService: DataViewsService;
usageCollection?: UsageCounter;
counterName: string;
id: string;
}

interface SwapRefResponse {
result: Array<{ id: string; type: string }>;
preview: boolean;
deleteSuccess?: boolean;
}

export const swapReference = async ({
dataViewsService,
usageCollection,
counterName,
id,
}: GetDataViewArgs) => {
usageCollection?.incrementCounter({ counterName });
return dataViewsService.get(id);
};

const idSchema = schema.string();

export const swapReferencesRoute = (
router: IRouter,
getStartServices: StartServicesAccessor<
DataViewsServerPluginStartDependencies,
DataViewsServerPluginStart
>,
usageCollection?: UsageCounter
) => {
router.versioned.post({ path: DATA_VIEW_SWAP_REFERENCES_PATH, access: 'public' }).addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
body: schema.object({
from_id: idSchema,
from_type: schema.maybe(schema.string()),
to_id: idSchema,
for_id: schema.maybe(schema.oneOf([idSchema, schema.arrayOf(idSchema)])),
for_type: schema.maybe(schema.string()),
preview: schema.maybe(schema.boolean()),
delete: schema.maybe(schema.boolean()),
}),
},
response: {
200: {
body: schema.object({
result: schema.arrayOf(schema.object({ id: idSchema, type: schema.string() })),
preview: schema.boolean(),
deleteSuccess: schema.maybe(schema.boolean()),
}),
},
},
},
},
router.handleLegacyErrors(
handleErrors(async (ctx, req, res) => {
const savedObjectsClient = (await ctx.core).savedObjects.client;
const [core] = await getStartServices();
const types = core.savedObjects.getTypeRegistry().getAllTypes();
const type = req.body.from_type || DATA_VIEW_SAVED_OBJECT_TYPE;
const preview = req.body.preview !== undefined ? req.body.preview : true;
const searchId =
!Array.isArray(req.body.for_id) && req.body.for_id !== undefined
? [req.body.for_id]
: req.body.for_id;

usageCollection?.incrementCounter({ counterName: 'swap_references' });

// verify 'to' object actually exists
try {
await savedObjectsClient.get(type, req.body.to_id);
} catch (e) {
throw new Error(`Could not find object with type ${type} and id ${req.body.to_id}`);
}

// assemble search params
const findParams: SavedObjectsFindOptions = {
type: types.map((t) => t.name),
hasReference: { type, id: req.body.from_id },
};

if (req.body.for_type) {
findParams.type = [req.body.for_type];
}

const { saved_objects: savedObjects } = await savedObjectsClient.find(findParams);

const filteredSavedObjects = searchId
? savedObjects.filter((so) => searchId?.includes(so.id))
: savedObjects;

// create summary of affected objects
const resultSummary = filteredSavedObjects.map((savedObject) => ({
id: savedObject.id,
type: savedObject.type,
}));

const body: SwapRefResponse = {
result: resultSummary,
preview,
};

// bail if preview
if (preview) {
return res.ok({
headers: {
'content-type': 'application/json',
},
body,
});
}

// iterate over list and update references
for (const savedObject of filteredSavedObjects) {
const updatedRefs = savedObject.references.map((ref) => {
if (ref.type === type && ref.id === req.body.from_id) {
return { ...ref, id: req.body.to_id };
} else {
return ref;
}
});

await savedObjectsClient.update(
savedObject.type,
savedObject.id,
{},
{
references: updatedRefs,
}
);
}

if (req.body.delete) {
const verifyNoMoreRefs = await savedObjectsClient.find(findParams);
if (verifyNoMoreRefs.total > 0) {
body.deleteSuccess = false;
} else {
await savedObjectsClient.delete(type, req.body.from_id);
body.deleteSuccess = true;
}
}

return res.ok({
headers: {
'content-type': 'application/json',
},
body,
});
})
)
);
};
1 change: 1 addition & 0 deletions test/api_integration/apis/data_views/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./integration'));
loadTestFile(require.resolve('./deprecations'));
loadTestFile(require.resolve('./has_user_index_pattern'));
loadTestFile(require.resolve('./swap_references'));
});
}
40 changes: 40 additions & 0 deletions test/api_integration/apis/data_views/swap_references/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { dataViewConfig } from '../constants';

export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');

describe('errors', () => {
it('returns 404 error on non-existing index_pattern', async () => {
const id = `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-${Date.now()}`;
const response = await supertest
.get(`${dataViewConfig.path}/${id}`)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION);

expect(response.status).to.be(404);
});

it('returns error when ID is too long', async () => {
const id = `xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx`;
const response = await supertest
.get(`${dataViewConfig.path}/${id}`)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION);

expect(response.status).to.be(400);
expect(response.body.message).to.be(
'[request params.id]: value has length [1759] but it must have a maximum length of [1000].'
);
});
});
}
16 changes: 16 additions & 0 deletions test/api_integration/apis/data_views/swap_references/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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 { FtrProviderContext } from '../../../ftr_provider_context';

export default function ({ loadTestFile }: FtrProviderContext) {
describe('swap_references', () => {
loadTestFile(require.resolve('./errors'));
loadTestFile(require.resolve('./main'));
});
}
Loading

0 comments on commit c3fffe3

Please sign in to comment.