mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Cases] - Update case generator (#223609)
## Summary Updates the logic around the test cases generator to allow for adding cases to additional environments example to test: ``` yarn generate:cases -c 1000 -o securitySolution ``` --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
26bb220e64
commit
0a07e18442
4 changed files with 246 additions and 163 deletions
|
@ -3,5 +3,8 @@
|
|||
"name": "@kbn/cases-plugin",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"license": "Elastic License 2.0"
|
||||
"license": "Elastic License 2.0",
|
||||
"scripts": {
|
||||
"generate:cases": "node scripts/generate_cases.js"
|
||||
}
|
||||
}
|
||||
|
|
231
x-pack/platform/plugins/shared/cases/scripts/cases_generator.ts
Normal file
231
x-pack/platform/plugins/shared/cases/scripts/cases_generator.ts
Normal file
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
import { KbnClient } from '@kbn/test';
|
||||
import { CA_CERT_PATH } from '@kbn/dev-utils';
|
||||
import { ToolingLog } from '@kbn/tooling-log';
|
||||
import type { KbnClientOptions } from '@kbn/test';
|
||||
import fs from 'fs';
|
||||
import pMap from 'p-map';
|
||||
import yargs from 'yargs';
|
||||
import { CaseSeverity, type CasePostRequest } from '../common';
|
||||
|
||||
const toolingLogger = new ToolingLog({
|
||||
level: 'info',
|
||||
writeTo: process.stdout,
|
||||
});
|
||||
|
||||
function updateURL({
|
||||
url,
|
||||
user,
|
||||
protocol,
|
||||
}: {
|
||||
url: string;
|
||||
user?: { username: string; password: string };
|
||||
protocol?: string;
|
||||
}): string {
|
||||
const urlObject = new URL(url);
|
||||
if (user) {
|
||||
urlObject.username = user.username;
|
||||
urlObject.password = user.password;
|
||||
}
|
||||
if (protocol) {
|
||||
urlObject.protocol = protocol;
|
||||
}
|
||||
return urlObject.href;
|
||||
}
|
||||
|
||||
const makeRequest = async ({
|
||||
url,
|
||||
newCase,
|
||||
path,
|
||||
username,
|
||||
password,
|
||||
ssl,
|
||||
}: {
|
||||
url: string;
|
||||
newCase: CasePostRequest;
|
||||
path: string;
|
||||
username: string;
|
||||
password: string;
|
||||
ssl: boolean;
|
||||
}) => {
|
||||
let ca: Buffer;
|
||||
const toolingLogOptions = { log: toolingLogger };
|
||||
|
||||
let updatedUrl = updateURL({
|
||||
url,
|
||||
user: { username, password },
|
||||
});
|
||||
|
||||
let kbnClientOptions: KbnClientOptions = {
|
||||
...toolingLogOptions,
|
||||
url: updatedUrl,
|
||||
};
|
||||
|
||||
if (ssl) {
|
||||
ca = fs.readFileSync(CA_CERT_PATH);
|
||||
updatedUrl = updateURL({
|
||||
url: updatedUrl,
|
||||
user: { username, password },
|
||||
protocol: 'https:',
|
||||
});
|
||||
kbnClientOptions = {
|
||||
...kbnClientOptions,
|
||||
certificateAuthorities: [ca],
|
||||
url: updatedUrl,
|
||||
};
|
||||
}
|
||||
const kbnClient = new KbnClient({ ...kbnClientOptions });
|
||||
|
||||
return kbnClient
|
||||
.request({
|
||||
method: 'POST',
|
||||
path,
|
||||
body: newCase,
|
||||
})
|
||||
.then(({ data }) => data)
|
||||
.catch(toolingLogger.error.bind(toolingLogger, `Error creating case: ${newCase.title}`));
|
||||
};
|
||||
|
||||
const createCase = (counter: number, owner: string, reqId: string): CasePostRequest => ({
|
||||
title: `Sample Case: ${reqId} - ${counter}`,
|
||||
tags: [],
|
||||
severity: CaseSeverity.LOW,
|
||||
description: `Auto generated case ${counter}`,
|
||||
assignees: [],
|
||||
connector: {
|
||||
id: 'none',
|
||||
name: 'none',
|
||||
// @ts-ignore
|
||||
type: '.none',
|
||||
fields: null,
|
||||
},
|
||||
settings: {
|
||||
syncAlerts: false,
|
||||
},
|
||||
owner: owner ?? 'cases',
|
||||
customFields: [],
|
||||
});
|
||||
|
||||
const getRandomString = (length: number) =>
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substring(2, length + 2);
|
||||
|
||||
const generateCases = async ({
|
||||
cases,
|
||||
space,
|
||||
username,
|
||||
password,
|
||||
kibana,
|
||||
ssl,
|
||||
}: {
|
||||
cases: CasePostRequest[];
|
||||
space: string;
|
||||
username: string;
|
||||
password: string;
|
||||
kibana: string;
|
||||
ssl: boolean;
|
||||
}) => {
|
||||
try {
|
||||
toolingLogger.info(
|
||||
`Creating ${cases.length} cases in ${space ? `space: ${space}` : 'default space'}`
|
||||
);
|
||||
const path = `${space ? `/s/${space}` : ''}/api/cases`;
|
||||
await pMap(
|
||||
cases,
|
||||
(newCase) => {
|
||||
return makeRequest({ url: kibana, path, newCase, username, password, ssl });
|
||||
},
|
||||
{ concurrency: 100 }
|
||||
);
|
||||
} catch (error) {
|
||||
toolingLogger.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
const argv = yargs.help().options({
|
||||
username: {
|
||||
alias: 'u',
|
||||
describe: 'username for kibana',
|
||||
type: 'string',
|
||||
default: 'elastic',
|
||||
},
|
||||
password: {
|
||||
alias: 'p',
|
||||
describe: 'password for kibana',
|
||||
type: 'string',
|
||||
default: 'changeme',
|
||||
},
|
||||
kibana: {
|
||||
alias: 'k',
|
||||
describe: 'kibana url',
|
||||
default: 'http://127.0.0.1:5601',
|
||||
type: 'string',
|
||||
},
|
||||
count: {
|
||||
alias: 'c',
|
||||
describe: 'Number of cases to generate',
|
||||
type: 'number',
|
||||
default: 10,
|
||||
},
|
||||
owners: {
|
||||
alias: 'o',
|
||||
describe:
|
||||
'solutions where the cases should be created. combination of securitySolution, observability, or cases',
|
||||
default: ['securitySolution', 'observability', 'cases'],
|
||||
type: 'array',
|
||||
},
|
||||
space: {
|
||||
alias: 's',
|
||||
describe: 'space where the cases should be created',
|
||||
default: '',
|
||||
type: 'string',
|
||||
},
|
||||
ssl: {
|
||||
alias: 'ssl',
|
||||
describe: 'Use https for non local environments',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
}).argv;
|
||||
|
||||
const { username, password, kibana, count, owners, space, ssl } = argv;
|
||||
const numCasesToCreate = Number(count);
|
||||
const potentialOwners = new Set(['securitySolution', 'observability', 'cases']);
|
||||
const invalidOwnerProvided = owners.some((owner) => !potentialOwners.has(owner));
|
||||
|
||||
if (invalidOwnerProvided) {
|
||||
toolingLogger.error('Only valid owners are securitySolution, observability, and cases');
|
||||
// eslint-disable-next-line no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const idForThisRequest = getRandomString(6);
|
||||
|
||||
const cases = Array(numCasesToCreate)
|
||||
.fill(null)
|
||||
.map((_, index) => {
|
||||
const owner = owners[Math.floor(Math.random() * owners.length)];
|
||||
return createCase(index + 1, owner, idForThisRequest);
|
||||
});
|
||||
|
||||
await generateCases({ cases, space, username, password, kibana, ssl });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
console.log(err);
|
||||
});
|
|
@ -5,161 +5,5 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
const http = require('http');
|
||||
const pMap = require('p-map');
|
||||
const yargs = require('yargs');
|
||||
|
||||
const username = 'elastic';
|
||||
const password = 'changeme';
|
||||
|
||||
const makeRequest = async ({ options, data }) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reqData = JSON.stringify(data);
|
||||
const reqOptions = {
|
||||
...options,
|
||||
rejectUnauthorized: false,
|
||||
requestCert: true,
|
||||
agent: false,
|
||||
headers: {
|
||||
...options.headers,
|
||||
Authorization: `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`,
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': reqData.length,
|
||||
'kbn-xsrf': 'true',
|
||||
},
|
||||
};
|
||||
|
||||
const req = http.request(reqOptions, (res) => {
|
||||
const body = [];
|
||||
|
||||
res.on('data', (chunk) => body.push(chunk));
|
||||
res.on('end', () => {
|
||||
const resString = Buffer.concat(body).toString();
|
||||
try {
|
||||
if (resString != null && resString.length > 0) {
|
||||
const res = JSON.parse(resString);
|
||||
if (res.statusCode && res.statusCode === 400) {
|
||||
reject(new Error(res.message));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
resolve(resString);
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
req.destroy();
|
||||
reject(new Error('Request time out'));
|
||||
});
|
||||
|
||||
req.write(reqData);
|
||||
req.end();
|
||||
});
|
||||
};
|
||||
|
||||
const getHostAndPort = () => ({
|
||||
host: '127.0.0.1',
|
||||
port: 5601,
|
||||
});
|
||||
|
||||
const createCase = (counter, owner) => ({
|
||||
title: `Sample Case ${counter}`,
|
||||
tags: [],
|
||||
severity: 'low',
|
||||
description: `Auto generated case ${counter}`,
|
||||
assignees: [],
|
||||
connector: {
|
||||
id: 'none',
|
||||
name: 'none',
|
||||
type: '.none',
|
||||
fields: null,
|
||||
},
|
||||
settings: {
|
||||
syncAlerts: false,
|
||||
},
|
||||
owner: owner ?? 'cases',
|
||||
customFields: [],
|
||||
});
|
||||
|
||||
const generateCases = async (cases, space) => {
|
||||
try {
|
||||
console.log(`Creating ${cases.length} cases in ${space ? `space: ${space}` : 'default space'}`);
|
||||
const path = space ? `/s/${space}/api/cases` : '/api/cases';
|
||||
await pMap(
|
||||
cases,
|
||||
(theCase) => {
|
||||
const options = {
|
||||
...getHostAndPort(),
|
||||
path,
|
||||
method: 'POST',
|
||||
};
|
||||
|
||||
return makeRequest({ options, data: theCase });
|
||||
},
|
||||
{ concurrency: 100 }
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
const argv = yargs.help().options({
|
||||
count: {
|
||||
alias: 'c',
|
||||
describe: 'number of cases to generate',
|
||||
type: 'number',
|
||||
default: 10,
|
||||
},
|
||||
owners: {
|
||||
alias: 'o',
|
||||
describe:
|
||||
'solutions where the cases should be created. combination of securitySolution, observability, or cases',
|
||||
default: 'cases',
|
||||
type: 'array',
|
||||
},
|
||||
space: {
|
||||
alias: 's',
|
||||
describe: 'space where the cases should be created',
|
||||
default: '',
|
||||
type: 'string',
|
||||
},
|
||||
}).argv;
|
||||
|
||||
const { count, owners, space } = argv;
|
||||
const numCasesToCreate = Number(count);
|
||||
const potentialOwners = new Set(['securitySolution', 'observability', 'cases']);
|
||||
|
||||
const invalidOwnerProvided = owners.some((owner) => !potentialOwners.has(owner));
|
||||
|
||||
if (invalidOwnerProvided) {
|
||||
console.error('Only valid owners are securitySolution, observability, and cases');
|
||||
// eslint-disable-next-line no-process-exit
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const cases = Array(numCasesToCreate)
|
||||
.fill(null)
|
||||
.map((_, index) => {
|
||||
const owner = owners[Math.floor(Math.random() * owners.length)];
|
||||
return createCase(index + 1, owner);
|
||||
});
|
||||
|
||||
await generateCases(cases, space);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
require('../../../../../../src/setup_node_env');
|
||||
require('./cases_generator');
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
{
|
||||
"extends": "../../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"outDir": "target/types"
|
||||
},
|
||||
"include": [
|
||||
"common/**/*",
|
||||
"public/**/*",
|
||||
"server/**/*",
|
||||
"scripts/**/*",
|
||||
"../../../../../typings/**/*"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
{
|
||||
"path": "../../../../../src/setup_node_env/tsconfig.json"
|
||||
},
|
||||
// optionalPlugins from ./kibana.json
|
||||
"@kbn/lens-plugin",
|
||||
"@kbn/security-plugin",
|
||||
|
@ -85,8 +89,9 @@
|
|||
"@kbn/logging",
|
||||
"@kbn/core-elasticsearch-client-server-mocks",
|
||||
"@kbn/core-test-helpers-model-versions",
|
||||
"@kbn/test",
|
||||
"@kbn/dev-utils",
|
||||
"@kbn/tooling-log"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
]
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue