edd904c1c4
The job factory will now accept an array of resourceSpecs that is a shorthand notation for memory, cpu, disk, and iops requirements. These specs get passed down to task groups. The task group factory will split the resource requirements near evenly (there is variance threshold) across all expected tasks. Allocations then construct task-resource objects based on the resources from the matching task.
260 lines
7.1 KiB
JavaScript
260 lines
7.1 KiB
JavaScript
import { assign } from '@ember/polyfills';
|
|
import { Factory, trait } from 'ember-cli-mirage';
|
|
import faker from 'nomad-ui/mirage/faker';
|
|
import { provide, pickOne } from '../utils';
|
|
import { DATACENTERS } from '../common';
|
|
|
|
const JOB_PREFIXES = provide(5, faker.hacker.abbreviation);
|
|
const JOB_TYPES = ['service', 'batch', 'system'];
|
|
const JOB_STATUSES = ['pending', 'running', 'dead'];
|
|
|
|
export default Factory.extend({
|
|
id: i =>
|
|
`${faker.helpers.randomize(
|
|
JOB_PREFIXES
|
|
)}-${faker.hacker.noun().dasherize()}-${i}`.toLowerCase(),
|
|
|
|
name() {
|
|
return this.id;
|
|
},
|
|
|
|
version: 1,
|
|
|
|
// When provided, the resourceSpec will inform how many task groups to create
|
|
// and how much of each resource that task group reserves.
|
|
//
|
|
// One task group, 256 MiB memory and 500 Mhz cpu
|
|
// 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 });
|
|
},
|
|
|
|
region: () => 'global',
|
|
type: () => faker.helpers.randomize(JOB_TYPES),
|
|
priority: () => faker.random.number(100),
|
|
allAtOnce: faker.random.boolean,
|
|
status: () => faker.helpers.randomize(JOB_STATUSES),
|
|
datacenters: () =>
|
|
faker.helpers.shuffle(DATACENTERS).slice(0, faker.random.number({ min: 1, max: 4 })),
|
|
|
|
childrenCount: () => faker.random.number({ min: 1, max: 2 }),
|
|
|
|
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',
|
|
}),
|
|
}),
|
|
|
|
parameterized: trait({
|
|
type: 'batch',
|
|
parameterized: true,
|
|
// parameterized details object
|
|
// serializer update for bool vs details object
|
|
parameterizedDetails: () => ({
|
|
MetaOptional: null,
|
|
MetaRequired: null,
|
|
Payload: faker.random.boolean() ? 'required' : null,
|
|
}),
|
|
}),
|
|
|
|
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',
|
|
}),
|
|
|
|
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',
|
|
parameterized: true,
|
|
dispatched: true,
|
|
payload: window.btoa(faker.lorem.sentence()),
|
|
}),
|
|
|
|
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,
|
|
|
|
// When true, the job will have no versions or deployments (and in turn no latest deployment)
|
|
noDeployments: false,
|
|
|
|
// When true, an evaluation with a high modify index and placement failures is created
|
|
failedPlacements: false,
|
|
|
|
// When true, no evaluations have failed placements
|
|
noFailedPlacements: false,
|
|
|
|
// When true, all task groups get the noHostVolumes trait
|
|
noHostVolumes: false,
|
|
|
|
// When true, allocations for this job will fail and reschedule, randomly succeeding or not
|
|
withRescheduling: false,
|
|
|
|
// When true, task groups will have services
|
|
withGroupServices: false,
|
|
|
|
// When true, only task groups and allocations are made
|
|
shallow: false,
|
|
|
|
afterCreate(job, server) {
|
|
if (!job.namespaceId) {
|
|
const namespace = server.db.namespaces.length ? pickOne(server.db.namespaces).id : null;
|
|
job.update({
|
|
namespace,
|
|
namespaceId: namespace,
|
|
});
|
|
} else {
|
|
job.update({
|
|
namespace: job.namespaceId,
|
|
});
|
|
}
|
|
|
|
const groupProps = {
|
|
job,
|
|
createAllocations: job.createAllocations,
|
|
withRescheduling: job.withRescheduling,
|
|
withServices: job.withGroupServices,
|
|
shallow: job.shallow,
|
|
};
|
|
|
|
if (job.groupTaskCount) {
|
|
groupProps.count = job.groupTaskCount;
|
|
}
|
|
|
|
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],
|
|
})
|
|
);
|
|
}
|
|
|
|
job.update({
|
|
taskGroupIds: groups.mapBy('id'),
|
|
});
|
|
|
|
const hasChildren = job.periodic || (job.parameterized && !job.parentId);
|
|
const jobSummary = server.create('job-summary', hasChildren ? 'withChildren' : 'withSummary', {
|
|
jobId: job.id,
|
|
groupNames: groups.mapBy('name'),
|
|
namespace: job.namespace,
|
|
});
|
|
|
|
job.update({
|
|
jobSummaryId: jobSummary.id,
|
|
});
|
|
|
|
const jobScale = server.create('job-scale', {
|
|
groupNames: groups.mapBy('name'),
|
|
jobId: job.id,
|
|
namespace: job.namespace,
|
|
shallow: job.shallow,
|
|
});
|
|
|
|
job.update({
|
|
jobScaleId: jobScale.id,
|
|
});
|
|
|
|
if (!job.noDeployments) {
|
|
Array(faker.random.number({ min: 1, max: 3 }))
|
|
.fill(null)
|
|
.map((_, index) => {
|
|
return server.create('job-version', {
|
|
job,
|
|
namespace: job.namespace,
|
|
version: index,
|
|
noActiveDeployment: job.noActiveDeployment,
|
|
activeDeployment: job.activeDeployment,
|
|
});
|
|
});
|
|
}
|
|
|
|
if (!job.shallow) {
|
|
const knownEvaluationProperties = {
|
|
job,
|
|
namespace: job.namespace,
|
|
};
|
|
server.createList(
|
|
'evaluation',
|
|
faker.random.number({ min: 1, max: 5 }),
|
|
knownEvaluationProperties
|
|
);
|
|
if (!job.noFailedPlacements) {
|
|
server.createList(
|
|
'evaluation',
|
|
faker.random.number(3),
|
|
'withPlacementFailures',
|
|
knownEvaluationProperties
|
|
);
|
|
}
|
|
|
|
if (job.failedPlacements) {
|
|
server.create(
|
|
'evaluation',
|
|
'withPlacementFailures',
|
|
assign(knownEvaluationProperties, {
|
|
modifyIndex: 4000,
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
if (job.periodic) {
|
|
// Create periodicChild jobs
|
|
server.createList('job', job.childrenCount, 'periodicChild', {
|
|
parentId: job.id,
|
|
namespaceId: job.namespaceId,
|
|
namespace: job.namespace,
|
|
createAllocations: job.createAllocations,
|
|
shallow: job.shallow,
|
|
});
|
|
}
|
|
|
|
if (job.parameterized && !job.parentId) {
|
|
// Create parameterizedChild jobs
|
|
server.createList('job', job.childrenCount, 'parameterizedChild', {
|
|
parentId: job.id,
|
|
namespaceId: job.namespaceId,
|
|
namespace: job.namespace,
|
|
createAllocations: job.createAllocations,
|
|
shallow: job.shallow,
|
|
});
|
|
}
|
|
},
|
|
});
|