2018-02-16 02:55:59 +00:00
|
|
|
import { assign } from '@ember/polyfills';
|
2019-09-26 18:47:07 +00:00
|
|
|
import { Factory, trait } from 'ember-cli-mirage';
|
2019-10-03 14:13:08 +00:00
|
|
|
import faker from 'nomad-ui/mirage/faker';
|
2020-02-13 23:47:01 +00:00
|
|
|
import { provide, pickOne } from '../utils';
|
2017-09-19 14:47:10 +00:00
|
|
|
import { DATACENTERS } from '../common';
|
|
|
|
|
2020-09-19 05:20:09 +00:00
|
|
|
const REF_TIME = new Date();
|
2017-09-19 14:47:10 +00:00
|
|
|
const JOB_PREFIXES = provide(5, faker.hacker.abbreviation);
|
2021-10-07 21:11:38 +00:00
|
|
|
const JOB_TYPES = ['service', 'batch', 'system', 'sysbatch'];
|
2017-09-19 14:47:10 +00:00
|
|
|
const JOB_STATUSES = ['pending', 'running', 'dead'];
|
|
|
|
|
|
|
|
export default Factory.extend({
|
2021-07-20 22:27:41 +00:00
|
|
|
id(i) {
|
|
|
|
if (this.parameterized && this.parentId) {
|
|
|
|
const shortUUID = faker.random.uuid().split('-')[0];
|
|
|
|
const dispatchId = `dispatch-${this.submitTime / 1000}-${shortUUID}`;
|
|
|
|
return `${this.parentId}/${dispatchId}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return `${faker.helpers.randomize(
|
2019-09-26 18:47:07 +00:00
|
|
|
JOB_PREFIXES
|
2021-07-20 22:27:41 +00:00
|
|
|
)}-${faker.hacker.noun().dasherize()}-${i}`.toLowerCase();
|
|
|
|
},
|
2018-08-16 00:00:08 +00:00
|
|
|
|
|
|
|
name() {
|
|
|
|
return this.id;
|
|
|
|
},
|
2017-09-19 14:47:10 +00:00
|
|
|
|
2020-05-01 21:29:24 +00:00
|
|
|
version: 1,
|
2020-09-19 05:20:09 +00:00
|
|
|
submitTime: () => faker.date.past(2 / 365, REF_TIME) * 1000000,
|
2020-05-01 21:29:24 +00:00
|
|
|
|
2020-08-24 16:24:32 +00:00
|
|
|
// When provided, the resourceSpec will inform how many task groups to create
|
|
|
|
// and how much of each resource that task group reserves.
|
|
|
|
//
|
2021-01-26 18:53:26 +00:00
|
|
|
// One task group, 256 MiB memory and 500 MHz cpu
|
2020-08-24 16:24:32 +00:00
|
|
|
// resourceSpec: ['M: 256, C: 500']
|
|
|
|
//
|
|
|
|
// Two task groups
|
|
|
|
// resourceSpec: ['M: 256, C: 500', 'M: 1024, C: 1200']
|
|
|
|
resourceSpec: null,
|
|
|
|
|
|
|
|
groupsCount() {
|
|
|
|
return this.resourceSpec ? this.resourceSpec.length : faker.random.number({ min: 1, max: 2 });
|
|
|
|
},
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
|
|
region: () => 'global',
|
2019-09-30 14:44:22 +00:00
|
|
|
type: () => faker.helpers.randomize(JOB_TYPES),
|
2017-11-29 23:36:34 +00:00
|
|
|
priority: () => faker.random.number(100),
|
2020-08-28 00:58:24 +00:00
|
|
|
allAtOnce: faker.random.boolean,
|
2019-09-30 14:44:22 +00:00
|
|
|
status: () => faker.helpers.randomize(JOB_STATUSES),
|
2019-09-26 18:47:07 +00:00
|
|
|
datacenters: () =>
|
|
|
|
faker.helpers.shuffle(DATACENTERS).slice(0, faker.random.number({ min: 1, max: 4 })),
|
2017-09-19 14:47:10 +00:00
|
|
|
|
2019-04-12 03:08:09 +00:00
|
|
|
childrenCount: () => faker.random.number({ min: 1, max: 2 }),
|
2018-01-30 21:19:24 +00:00
|
|
|
|
|
|
|
periodic: trait({
|
|
|
|
type: 'batch',
|
|
|
|
periodic: true,
|
|
|
|
// periodic details object
|
|
|
|
// serializer update for bool vs details object
|
|
|
|
periodicDetails: () => ({
|
|
|
|
Enabled: true,
|
|
|
|
ProhibitOverlap: true,
|
|
|
|
Spec: '*/5 * * * * *',
|
|
|
|
SpecType: 'cron',
|
|
|
|
TimeZone: 'UTC',
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
|
2021-10-07 21:11:38 +00:00
|
|
|
periodicSysbatch: trait({
|
|
|
|
type: 'sysbatch',
|
|
|
|
periodic: true,
|
|
|
|
// periodic details object
|
|
|
|
// serializer update for bool vs details object
|
|
|
|
periodicDetails: () => ({
|
|
|
|
Enabled: true,
|
|
|
|
ProhibitOverlap: true,
|
|
|
|
Spec: '*/5 * * * * *',
|
|
|
|
SpecType: 'cron',
|
|
|
|
TimeZone: 'UTC',
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
|
2018-01-30 21:19:24 +00:00
|
|
|
parameterized: trait({
|
|
|
|
type: 'batch',
|
|
|
|
parameterized: true,
|
2021-07-20 22:27:41 +00:00
|
|
|
// parameterized job object
|
2018-01-30 21:19:24 +00:00
|
|
|
// serializer update for bool vs details object
|
2021-07-20 22:27:41 +00:00
|
|
|
parameterizedJob: () => ({
|
|
|
|
MetaOptional: generateMetaFields(faker.random.number(10), 'optional'),
|
|
|
|
MetaRequired: generateMetaFields(faker.random.number(10), 'required'),
|
2019-10-03 14:13:08 +00:00
|
|
|
Payload: faker.random.boolean() ? 'required' : null,
|
2018-01-30 21:19:24 +00:00
|
|
|
}),
|
|
|
|
}),
|
|
|
|
|
2021-10-07 21:11:38 +00:00
|
|
|
parameterizedSysbatch: trait({
|
|
|
|
type: 'sysbatch',
|
|
|
|
parameterized: true,
|
|
|
|
// parameterized job object
|
|
|
|
// serializer update for bool vs details object
|
|
|
|
parameterizedJob: () => ({
|
|
|
|
MetaOptional: generateMetaFields(faker.random.number(10), 'optional'),
|
|
|
|
MetaRequired: generateMetaFields(faker.random.number(10), 'required'),
|
|
|
|
Payload: faker.random.boolean() ? 'required' : null,
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
|
2018-01-30 21:19:24 +00:00
|
|
|
periodicChild: trait({
|
|
|
|
// Periodic children need a parent job,
|
|
|
|
// It is the Periodic job's responsibility to create
|
|
|
|
// periodicChild jobs and provide a parent job.
|
|
|
|
type: 'batch',
|
|
|
|
}),
|
|
|
|
|
2021-10-07 21:11:38 +00:00
|
|
|
periodicSysbatchChild: trait({
|
|
|
|
// Periodic children need a parent job,
|
|
|
|
// It is the Periodic job's responsibility to create
|
|
|
|
// periodicChild jobs and provide a parent job.
|
|
|
|
type: 'sysbatch',
|
|
|
|
}),
|
|
|
|
|
2018-01-30 21:19:24 +00:00
|
|
|
parameterizedChild: trait({
|
|
|
|
// Parameterized children need a parent job,
|
|
|
|
// It is the Parameterized job's responsibility to create
|
|
|
|
// parameterizedChild jobs and provide a parent job.
|
|
|
|
type: 'batch',
|
2018-11-08 01:07:40 +00:00
|
|
|
parameterized: true,
|
2018-11-08 05:04:27 +00:00
|
|
|
dispatched: true,
|
2018-01-30 21:19:24 +00:00
|
|
|
payload: window.btoa(faker.lorem.sentence()),
|
|
|
|
}),
|
2017-09-19 14:47:10 +00:00
|
|
|
|
2021-10-07 21:11:38 +00:00
|
|
|
parameterizedSysbatchChild: trait({
|
|
|
|
// Parameterized children need a parent job,
|
|
|
|
// It is the Parameterized job's responsibility to create
|
|
|
|
// parameterizedChild jobs and provide a parent job.
|
|
|
|
type: 'sysbatch',
|
|
|
|
parameterized: true,
|
|
|
|
dispatched: true,
|
|
|
|
payload: window.btoa(faker.lorem.sentence()),
|
|
|
|
}),
|
|
|
|
|
2017-09-19 14:47:10 +00:00
|
|
|
createIndex: i => i,
|
|
|
|
modifyIndex: () => faker.random.number({ min: 10, max: 2000 }),
|
|
|
|
|
|
|
|
// Directive used to control sub-resources
|
|
|
|
|
|
|
|
// When false, no allocations are made
|
|
|
|
createAllocations: true,
|
|
|
|
|
|
|
|
// When true, deployments for the job will never have a 'running' status
|
|
|
|
noActiveDeployment: false,
|
|
|
|
|
|
|
|
// When true, deployments for the job will always have a 'running' status
|
|
|
|
activeDeployment: false,
|
|
|
|
|
2018-07-30 22:20:58 +00:00
|
|
|
// When true, the job will have no versions or deployments (and in turn no latest deployment)
|
|
|
|
noDeployments: false,
|
|
|
|
|
2017-11-29 23:36:34 +00:00
|
|
|
// When true, an evaluation with a high modify index and placement failures is created
|
|
|
|
failedPlacements: false,
|
|
|
|
|
2017-11-30 00:29:32 +00:00
|
|
|
// When true, no evaluations have failed placements
|
|
|
|
noFailedPlacements: false,
|
|
|
|
|
2020-02-13 23:47:01 +00:00
|
|
|
// When true, all task groups get the noHostVolumes trait
|
|
|
|
noHostVolumes: false,
|
|
|
|
|
2018-05-04 20:08:30 +00:00
|
|
|
// When true, allocations for this job will fail and reschedule, randomly succeeding or not
|
|
|
|
withRescheduling: false,
|
|
|
|
|
2019-09-04 14:39:56 +00:00
|
|
|
// When true, task groups will have services
|
|
|
|
withGroupServices: false,
|
|
|
|
|
2020-10-29 12:46:42 +00:00
|
|
|
// When true, dynamic application sizing recommendations will be made
|
|
|
|
createRecommendations: false,
|
|
|
|
|
2019-04-12 03:08:09 +00:00
|
|
|
// When true, only task groups and allocations are made
|
|
|
|
shallow: false,
|
|
|
|
|
2017-09-19 14:47:10 +00:00
|
|
|
afterCreate(job, server) {
|
2017-10-11 20:44:27 +00:00
|
|
|
if (!job.namespaceId) {
|
2017-10-23 17:18:14 +00:00
|
|
|
const namespace = server.db.namespaces.length ? pickOne(server.db.namespaces).id : null;
|
2017-10-11 20:44:27 +00:00
|
|
|
job.update({
|
2017-10-23 17:18:14 +00:00
|
|
|
namespace,
|
|
|
|
namespaceId: namespace,
|
2017-10-11 20:44:27 +00:00
|
|
|
});
|
2017-10-23 23:59:30 +00:00
|
|
|
} else {
|
|
|
|
job.update({
|
|
|
|
namespace: job.namespaceId,
|
|
|
|
});
|
2017-10-11 20:44:27 +00:00
|
|
|
}
|
|
|
|
|
2020-02-13 23:47:01 +00:00
|
|
|
const groupProps = {
|
2018-02-16 02:55:59 +00:00
|
|
|
job,
|
|
|
|
createAllocations: job.createAllocations,
|
2018-05-04 20:08:30 +00:00
|
|
|
withRescheduling: job.withRescheduling,
|
2019-09-04 14:39:56 +00:00
|
|
|
withServices: job.withGroupServices,
|
2020-10-29 12:46:42 +00:00
|
|
|
createRecommendations: job.createRecommendations,
|
2019-04-12 03:08:09 +00:00
|
|
|
shallow: job.shallow,
|
2020-02-13 23:47:01 +00:00
|
|
|
};
|
2020-03-24 23:22:16 +00:00
|
|
|
|
|
|
|
if (job.groupTaskCount) {
|
|
|
|
groupProps.count = job.groupTaskCount;
|
|
|
|
}
|
|
|
|
|
2020-08-24 16:24:32 +00:00
|
|
|
let groups;
|
|
|
|
if (job.noHostVolumes) {
|
|
|
|
groups = provide(job.groupsCount, (_, idx) =>
|
|
|
|
server.create('task-group', 'noHostVolumes', {
|
|
|
|
...groupProps,
|
|
|
|
resourceSpec: job.resourceSpec && job.resourceSpec.length && job.resourceSpec[idx],
|
|
|
|
})
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
groups = provide(job.groupsCount, (_, idx) =>
|
|
|
|
server.create('task-group', {
|
|
|
|
...groupProps,
|
|
|
|
resourceSpec: job.resourceSpec && job.resourceSpec.length && job.resourceSpec[idx],
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
2018-02-16 02:55:59 +00:00
|
|
|
|
|
|
|
job.update({
|
|
|
|
taskGroupIds: groups.mapBy('id'),
|
|
|
|
});
|
|
|
|
|
2018-11-08 05:04:27 +00:00
|
|
|
const hasChildren = job.periodic || (job.parameterized && !job.parentId);
|
2018-01-30 21:19:24 +00:00
|
|
|
const jobSummary = server.create('job-summary', hasChildren ? 'withChildren' : 'withSummary', {
|
2020-08-28 00:58:24 +00:00
|
|
|
jobId: job.id,
|
2017-09-19 14:47:10 +00:00
|
|
|
groupNames: groups.mapBy('name'),
|
2018-02-16 02:55:59 +00:00
|
|
|
namespace: job.namespace,
|
2017-09-19 14:47:10 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
job.update({
|
|
|
|
jobSummaryId: jobSummary.id,
|
|
|
|
});
|
|
|
|
|
2020-07-25 04:36:43 +00:00
|
|
|
const jobScale = server.create('job-scale', {
|
|
|
|
groupNames: groups.mapBy('name'),
|
|
|
|
jobId: job.id,
|
|
|
|
namespace: job.namespace,
|
|
|
|
shallow: job.shallow,
|
|
|
|
});
|
|
|
|
|
|
|
|
job.update({
|
|
|
|
jobScaleId: jobScale.id,
|
|
|
|
});
|
|
|
|
|
2018-07-30 22:20:58 +00:00
|
|
|
if (!job.noDeployments) {
|
2019-04-12 01:15:35 +00:00
|
|
|
Array(faker.random.number({ min: 1, max: 3 }))
|
2018-07-30 22:20:58 +00:00
|
|
|
.fill(null)
|
|
|
|
.map((_, index) => {
|
|
|
|
return server.create('job-version', {
|
|
|
|
job,
|
|
|
|
namespace: job.namespace,
|
|
|
|
version: index,
|
|
|
|
noActiveDeployment: job.noActiveDeployment,
|
|
|
|
activeDeployment: job.activeDeployment,
|
|
|
|
});
|
2017-09-19 14:47:10 +00:00
|
|
|
});
|
2018-07-30 22:20:58 +00:00
|
|
|
}
|
2017-11-29 23:36:34 +00:00
|
|
|
|
2019-04-12 03:08:09 +00:00
|
|
|
if (!job.shallow) {
|
|
|
|
const knownEvaluationProperties = {
|
|
|
|
job,
|
|
|
|
namespace: job.namespace,
|
|
|
|
};
|
2018-02-16 02:55:59 +00:00
|
|
|
server.createList(
|
|
|
|
'evaluation',
|
2019-04-12 03:08:09 +00:00
|
|
|
faker.random.number({ min: 1, max: 5 }),
|
2018-02-16 02:55:59 +00:00
|
|
|
knownEvaluationProperties
|
|
|
|
);
|
2019-04-12 03:08:09 +00:00
|
|
|
if (!job.noFailedPlacements) {
|
|
|
|
server.createList(
|
|
|
|
'evaluation',
|
|
|
|
faker.random.number(3),
|
|
|
|
'withPlacementFailures',
|
|
|
|
knownEvaluationProperties
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (job.failedPlacements) {
|
|
|
|
server.create(
|
|
|
|
'evaluation',
|
|
|
|
'withPlacementFailures',
|
|
|
|
assign(knownEvaluationProperties, {
|
|
|
|
modifyIndex: 4000,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
2017-11-29 23:36:34 +00:00
|
|
|
}
|
2018-01-30 21:19:24 +00:00
|
|
|
|
|
|
|
if (job.periodic) {
|
2021-10-07 21:11:38 +00:00
|
|
|
let childType;
|
|
|
|
switch (job.type) {
|
|
|
|
case 'batch':
|
|
|
|
childType = 'periodicChild';
|
|
|
|
break;
|
|
|
|
case 'sysbatch':
|
|
|
|
childType = 'periodicSysbatchChild';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create child jobs
|
|
|
|
server.createList('job', job.childrenCount, childType, {
|
2018-01-30 21:19:24 +00:00
|
|
|
parentId: job.id,
|
|
|
|
namespaceId: job.namespaceId,
|
|
|
|
namespace: job.namespace,
|
2021-10-07 21:11:38 +00:00
|
|
|
datacenters: job.datacenters,
|
2018-01-31 22:01:13 +00:00
|
|
|
createAllocations: job.createAllocations,
|
2019-04-12 03:08:09 +00:00
|
|
|
shallow: job.shallow,
|
2018-01-30 21:19:24 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-11-08 05:04:27 +00:00
|
|
|
if (job.parameterized && !job.parentId) {
|
2021-10-07 21:11:38 +00:00
|
|
|
let childType;
|
|
|
|
switch (job.type) {
|
|
|
|
case 'batch':
|
|
|
|
childType = 'parameterizedChild';
|
|
|
|
break;
|
|
|
|
case 'sysbatch':
|
|
|
|
childType = 'parameterizedSysbatchChild';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create child jobs
|
|
|
|
server.createList('job', job.childrenCount, childType, {
|
2018-01-30 21:19:24 +00:00
|
|
|
parentId: job.id,
|
|
|
|
namespaceId: job.namespaceId,
|
|
|
|
namespace: job.namespace,
|
2021-10-07 21:11:38 +00:00
|
|
|
datacenters: job.datacenters,
|
2018-01-31 22:01:13 +00:00
|
|
|
createAllocations: job.createAllocations,
|
2019-04-12 03:08:09 +00:00
|
|
|
shallow: job.shallow,
|
2018-01-30 21:19:24 +00:00
|
|
|
});
|
|
|
|
}
|
2017-09-19 14:47:10 +00:00
|
|
|
},
|
|
|
|
});
|
2021-07-20 22:27:41 +00:00
|
|
|
|
|
|
|
function generateMetaFields(num, prefix = '') {
|
|
|
|
// Use an object to avoid duplicate meta fields.
|
|
|
|
// The prefix param helps to avoid duplicate entries across function calls.
|
|
|
|
let meta = {};
|
|
|
|
for (let i = 0; i < num; i++) {
|
|
|
|
const field = `${prefix}-${faker.hacker.noun()}`;
|
|
|
|
meta[field] = true;
|
|
|
|
}
|
|
|
|
return Object.keys(meta);
|
|
|
|
}
|