github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/mirage/factories/allocation.js (about)

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