import { inject as service } from '@ember/service'; import { computed } from '@ember/object'; import Model from 'ember-data/model'; import attr from 'ember-data/attr'; import { belongsTo } from 'ember-data/relationships'; import { fragment, fragmentArray } from 'ember-data-model-fragments/attributes'; import intersection from 'npm:lodash.intersection'; import shortUUIDProperty from '../utils/properties/short-uuid'; import AllocationStats from '../utils/classes/allocation-stats'; const STATUS_ORDER = { pending: 1, running: 2, complete: 3, failed: 4, lost: 5, }; export default Model.extend({ token: service(), shortId: shortUUIDProperty('id'), job: belongsTo('job'), node: belongsTo('node'), name: attr('string'), taskGroupName: attr('string'), resources: fragment('resources'), modifyIndex: attr('number'), modifyTime: attr('date'), jobVersion: attr('number'), // TEMPORARY: https://github.com/emberjs/data/issues/5209 originalJobId: attr('string'), clientStatus: attr('string'), desiredStatus: attr('string'), statusIndex: computed('clientStatus', function() { return STATUS_ORDER[this.get('clientStatus')] || 100; }), // When allocations are server-side rescheduled, a paper trail // is left linking all reschedule attempts. previousAllocation: belongsTo('allocation', { inverse: 'nextAllocation' }), nextAllocation: belongsTo('allocation', { inverse: 'previousAllocation' }), followUpEvaluation: belongsTo('evaluation'), statusClass: computed('clientStatus', function() { const classMap = { pending: 'is-pending', running: 'is-primary', complete: 'is-complete', failed: 'is-error', lost: 'is-light', }; return classMap[this.get('clientStatus')] || 'is-dark'; }), taskGroup: computed('taskGroupName', 'job.taskGroups.[]', function() { const taskGroups = this.get('job.taskGroups'); return taskGroups && taskGroups.findBy('name', this.get('taskGroupName')); }), unhealthyDrivers: computed('taskGroup.drivers.[]', 'node.unhealthyDriverNames.[]', function() { const taskGroupUnhealthyDrivers = this.get('taskGroup.drivers'); const nodeUnhealthyDrivers = this.get('node.unhealthyDriverNames'); if (taskGroupUnhealthyDrivers && nodeUnhealthyDrivers) { return intersection(taskGroupUnhealthyDrivers, nodeUnhealthyDrivers); } return []; }), fetchStats() { return this.get('token') .authorizedRequest(`/v1/client/allocation/${this.get('id')}/stats`) .then(res => res.json()) .then(json => { return new AllocationStats({ stats: json, allocation: this, }); }); }, states: fragmentArray('task-state'), rescheduleEvents: fragmentArray('reschedule-event'), hasRescheduleEvents: computed('rescheduleEvents.length', 'nextAllocation', function() { return this.get('rescheduleEvents.length') > 0 || this.get('nextAllocation'); }), hasStoppedRescheduling: computed( 'nextAllocation', 'clientStatus', 'followUpEvaluation', function() { return ( !this.get('nextAllocation.content') && !this.get('followUpEvaluation.content') && this.get('clientStatus') === 'failed' ); } ), });