[ML] Retain created_by setting when exporting anomaly detection jobs (#167319)

When exporting an anomaly detection job, it would be useful if the
original `created_by` property was not removed from the job config.


Related to
https://github.com/elastic/kibana/pull/167021#discussion_r1337007611
Related PR https://github.com/elastic/kibana/pull/88898
This commit is contained in:
James Gowdy 2023-09-27 18:45:36 +01:00 committed by GitHub
parent 55a86ba120
commit 354efc2fc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 14 deletions

View file

@ -30,7 +30,9 @@ export class JobsExportService {
constructor(private _mlApiServices: MlApiServices) {}
public async exportAnomalyDetectionJobs(jobIds: string[]) {
const configs = await Promise.all(jobIds.map(this._mlApiServices.jobs.jobForCloning));
const configs = await Promise.all(
jobIds.map((id) => this._mlApiServices.jobs.jobForCloning(id, true))
);
this._export(configs, 'anomaly-detector');
}

View file

@ -67,8 +67,8 @@ export const jobsApiProvider = (httpService: HttpService) => ({
});
},
jobForCloning(jobId: string) {
const body = JSON.stringify({ jobId });
jobForCloning(jobId: string, retainCreatedBy = false) {
const body = JSON.stringify({ jobId, retainCreatedBy });
return httpService.http<{ job?: Job; datafeed?: Datafeed } | undefined>({
path: `${ML_INTERNAL_BASE_PATH}/jobs/job_for_cloning`,
method: 'POST',

View file

@ -315,22 +315,30 @@ export function jobsProvider(
return { jobs, jobsMap };
}
async function getJobForCloning(jobId: string) {
const [jobResults, datafeedResult] = await Promise.all([
async function getJobForCloning(jobId: string, retainCreatedBy = false) {
const [jobResults, datafeedResult, fullJobResults] = await Promise.all([
mlClient.getJobs({ job_id: jobId, exclude_generated: true }),
getDatafeedByJobId(jobId, true),
...(retainCreatedBy ? [mlClient.getJobs({ job_id: jobId })] : []),
]);
const result: { datafeed?: Datafeed; job?: Job } = { job: undefined, datafeed: undefined };
if (datafeedResult && datafeedResult.job_id === jobId) {
result.datafeed = datafeedResult;
}
if (jobResults && jobResults.jobs) {
const job = jobResults.jobs.find((j) => j.job_id === jobId);
if (job) {
removeUnClonableCustomSettings(job);
result.job = job;
if (jobResults?.jobs?.length > 0) {
const job = jobResults.jobs[0];
removeUnClonableCustomSettings(job);
// to retain the created by property we need to add it back in
// from the job which hasn't been loaded with exclude_generated: true
if (retainCreatedBy && fullJobResults?.jobs?.length > 0) {
const fullJob = fullJobResults.jobs[0];
if (fullJob.custom_settings?.created_by) {
job.custom_settings.created_by = fullJob.custom_settings.created_by;
}
}
result.job = job;
}
return result;
}

View file

@ -30,7 +30,7 @@ import {
deleteJobsSchema,
} from './schemas/job_service_schema';
import { jobIdSchema } from './schemas/anomaly_detectors_schema';
import { jobForCloningSchema, jobIdSchema } from './schemas/anomaly_detectors_schema';
import { jobServiceProvider } from '../models/job_service';
import { getAuthorizationHeader } from '../lib/request_authorization';
@ -428,16 +428,16 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) {
version: '1',
validate: {
request: {
body: jobIdSchema,
body: jobForCloningSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { getJobForCloning } = jobServiceProvider(client, mlClient);
const { jobId } = request.body;
const { jobId, retainCreatedBy } = request.body;
const resp = await getJobForCloning(jobId);
const resp = await getJobForCloning(jobId, retainCreatedBy);
return response.ok({
body: resp,
});

View file

@ -211,3 +211,10 @@ export const forceQuerySchema = schema.object({
/** force close */
force: schema.maybe(schema.boolean()),
});
export const jobForCloningSchema = schema.object({
/** Whether to retain the created_by custom setting. */
retainCreatedBy: schema.maybe(schema.boolean()),
/** Job ID */
jobId: schema.string(),
});