github.com/hernad/nomad@v1.6.112/ui/mirage/factories/allocation.js (about) 1 /** 2 * Copyright (c) HashiCorp, Inc. 3 * SPDX-License-Identifier: MPL-2.0 4 */ 5 6 import Ember from 'ember'; 7 import moment from 'moment'; 8 import { Factory, trait } from 'ember-cli-mirage'; 9 import faker from 'nomad-ui/mirage/faker'; 10 import { provide, pickOne } from '../utils'; 11 import { generateResources } from '../common'; 12 13 const UUIDS = provide(100, faker.random.uuid.bind(faker.random)); 14 const CLIENT_STATUSES = ['pending', 'running', 'complete', 'failed', 'lost']; 15 const DESIRED_STATUSES = ['run', 'stop', 'evict']; 16 const REF_TIME = new Date(); 17 18 export default Factory.extend({ 19 id: (i) => (i >= 100 ? `${UUIDS[i % 100]}-${i}` : UUIDS[i]), 20 21 jobVersion: 1, 22 23 modifyIndex: () => faker.random.number({ min: 10, max: 2000 }), 24 modifyTime: () => faker.date.past(2 / 365, REF_TIME) * 1000000, 25 26 createIndex: () => faker.random.number({ min: 10, max: 2000 }), 27 createTime() { 28 return ( 29 faker.date.past(2 / 365, new Date(this.modifyTime / 1000000)) * 1000000 30 ); 31 }, 32 33 namespace: null, 34 35 clientStatus() { 36 return this.forceRunningClientStatus 37 ? 'running' 38 : faker.helpers.randomize(CLIENT_STATUSES); 39 }, 40 41 desiredStatus: () => faker.helpers.randomize(DESIRED_STATUSES), 42 43 // When true, doesn't create any resources, state, or events 44 shallow: false, 45 46 // When true, sets the client status to running 47 forceRunningClientStatus: false, 48 49 withTaskWithPorts: trait({ 50 afterCreate(allocation, server) { 51 const taskGroup = server.db.taskGroups.findBy({ 52 name: allocation.taskGroup, 53 }); 54 const resources = taskGroup.taskIds.map((id) => { 55 const task = server.db.tasks.find(id); 56 return server.create('task-resource', { 57 allocation, 58 name: task.name, 59 resources: generateResources({ 60 CPU: task.resources.CPU, 61 MemoryMB: task.resources.MemoryMB, 62 DiskMB: task.resources.DiskMB, 63 networks: { minPorts: 1 }, 64 }), 65 }); 66 }); 67 68 allocation.update({ taskResourceIds: resources.mapBy('id') }); 69 }, 70 }), 71 72 withoutTaskWithPorts: trait({ 73 afterCreate(allocation, server) { 74 const taskGroup = server.db.taskGroups.findBy({ 75 name: allocation.taskGroup, 76 }); 77 const resources = taskGroup.taskIds.map((id) => { 78 const task = server.db.tasks.find(id); 79 return server.create('task-resource', { 80 allocation, 81 name: task.name, 82 resources: generateResources({ 83 CPU: task.resources.CPU, 84 MemoryMB: task.resources.MemoryMB, 85 DiskMB: task.resources.DiskMB, 86 networks: { minPorts: 0, maxPorts: 0 }, 87 }), 88 }); 89 }); 90 91 allocation.update({ taskResourceIds: resources.mapBy('id') }); 92 }, 93 }), 94 95 rescheduleAttempts: 0, 96 rescheduleSuccess: false, 97 98 rescheduled: trait({ 99 // Create another allocation carrying the events of this as well as the reschduleSuccess state. 100 // Pass along rescheduleAttempts after decrementing. 101 // After rescheduleAttempts hits zero, a final allocation is made with no nextAllocation and 102 // a clientStatus of failed or running, depending on rescheduleSuccess 103 afterCreate(allocation, server) { 104 const attempts = allocation.rescheduleAttempts - 1; 105 const previousEvents = 106 (allocation.rescheduleTracker && allocation.rescheduleTracker.Events) || 107 []; 108 109 let rescheduleTime; 110 if (previousEvents.length) { 111 const lastEvent = previousEvents[previousEvents.length - 1]; 112 rescheduleTime = moment(lastEvent.RescheduleTime / 1000000).add( 113 5, 114 'minutes' 115 ); 116 } else { 117 rescheduleTime = faker.date.past(2 / 365, REF_TIME); 118 } 119 120 rescheduleTime *= 1000000; 121 122 const rescheduleTracker = { 123 Events: previousEvents.concat([ 124 { 125 PrevAllocID: allocation.id, 126 PrevNodeID: null, //allocation.node.id, 127 RescheduleTime: rescheduleTime, 128 }, 129 ]), 130 }; 131 132 let nextAllocation; 133 if (attempts > 0) { 134 nextAllocation = server.create('allocation', 'rescheduled', { 135 rescheduleAttempts: Math.max(attempts, 0), 136 rescheduleSuccess: allocation.rescheduleSuccess, 137 previousAllocation: allocation.id, 138 shallow: allocation.shallow, 139 clientStatus: 'failed', 140 rescheduleTracker, 141 followupEvalId: server.create('evaluation', { 142 waitUntil: rescheduleTime, 143 }).id, 144 }); 145 } else { 146 nextAllocation = server.create('allocation', { 147 previousAllocation: allocation.id, 148 clientStatus: allocation.rescheduleSuccess ? 'running' : 'failed', 149 shallow: allocation.shallow, 150 rescheduleTracker, 151 }); 152 } 153 154 allocation.update({ 155 nextAllocation: nextAllocation.id, 156 clientStatus: 'failed', 157 }); 158 }, 159 }), 160 161 preempted: trait({ 162 afterCreate(allocation, server) { 163 const preempter = server.create('allocation', { 164 preemptedAllocations: [allocation.id], 165 }); 166 allocation.update({ preemptedByAllocation: preempter.id }); 167 }, 168 }), 169 170 preempter: trait({ 171 afterCreate(allocation, server) { 172 const preempted = server.create('allocation', { 173 preemptedByAllocation: allocation.id, 174 }); 175 allocation.update({ preemptedAllocations: [preempted.id] }); 176 }, 177 }), 178 179 afterCreate(allocation, server) { 180 Ember.assert( 181 '[Mirage] No jobs! make sure jobs are created before allocations', 182 server.db.jobs.length 183 ); 184 Ember.assert( 185 '[Mirage] No nodes! make sure nodes are created before allocations', 186 server.db.nodes.length 187 ); 188 189 const job = allocation.jobId 190 ? server.db.jobs.find(allocation.jobId) 191 : pickOne(server.db.jobs); 192 const namespace = allocation.namespace || job.namespace; 193 const node = allocation.nodeId 194 ? server.db.nodes.find(allocation.nodeId) 195 : pickOne(server.db.nodes); 196 const taskGroup = allocation.taskGroup 197 ? server.db.taskGroups.findBy({ name: allocation.taskGroup }) 198 : pickOne(server.db.taskGroups.where({ jobId: job.id })); 199 200 allocation.update({ 201 namespace, 202 jobId: job.id, 203 nodeId: node.id, 204 taskStateIds: [], 205 taskResourceIds: [], 206 taskGroup: taskGroup.name, 207 name: allocation.name || `${taskGroup.name}.[${faker.random.number(10)}]`, 208 }); 209 210 if (!allocation.shallow) { 211 const states = taskGroup.taskIds.map((id) => 212 server.create('task-state', { 213 allocation, 214 name: server.db.tasks.find(id).name, 215 }) 216 ); 217 218 const resources = taskGroup.taskIds.map((id) => { 219 const task = server.db.tasks.find(id); 220 return server.create('task-resource', { 221 allocation, 222 name: task.name, 223 resources: task.originalResources, 224 }); 225 }); 226 227 allocation.update({ 228 taskStateIds: 229 allocation.clientStatus === 'pending' ? [] : states.mapBy('id'), 230 taskResourceIds: resources.mapBy('id'), 231 }); 232 233 // Each allocation has a corresponding allocation stats running on some client. 234 // Create that record, even though it's not a relationship. 235 server.create('client-allocation-stat', { 236 id: allocation.id, 237 _taskNames: states.mapBy('name'), 238 }); 239 } 240 }, 241 });