2023-04-10 15:36:59 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) HashiCorp, Inc.
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
|
|
*/
|
|
|
|
|
2017-12-15 21:39:18 +00:00
|
|
|
import { inject as service } from '@ember/service';
|
|
|
|
import { computed } from '@ember/object';
|
2020-05-13 04:28:40 +00:00
|
|
|
import { equal, none } from '@ember/object/computed';
|
2021-02-17 21:01:44 +00:00
|
|
|
import Model from '@ember-data/model';
|
|
|
|
import { attr, belongsTo, hasMany } from '@ember-data/model';
|
2017-09-19 14:47:10 +00:00
|
|
|
import { fragment, fragmentArray } from 'ember-data-model-fragments/attributes';
|
2022-08-26 22:02:12 +00:00
|
|
|
import isEqual from 'lodash.isequal';
|
2018-07-06 20:38:57 +00:00
|
|
|
import intersection from 'lodash.intersection';
|
2017-09-19 14:47:10 +00:00
|
|
|
import shortUUIDProperty from '../utils/properties/short-uuid';
|
2020-06-10 13:49:16 +00:00
|
|
|
import classic from 'ember-classic-decorator';
|
2017-09-19 14:47:10 +00:00
|
|
|
|
2017-10-18 00:48:52 +00:00
|
|
|
const STATUS_ORDER = {
|
|
|
|
pending: 1,
|
|
|
|
running: 2,
|
|
|
|
complete: 3,
|
2022-04-22 15:25:02 +00:00
|
|
|
unknown: 4,
|
|
|
|
failed: 5,
|
|
|
|
lost: 6,
|
2017-10-18 00:48:52 +00:00
|
|
|
};
|
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@classic
|
|
|
|
export default class Allocation extends Model {
|
|
|
|
@service token;
|
2022-08-26 22:02:12 +00:00
|
|
|
@service store;
|
2017-10-19 02:04:19 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@shortUUIDProperty('id') shortId;
|
|
|
|
@belongsTo('job') job;
|
|
|
|
@belongsTo('node') node;
|
2021-12-17 21:55:40 +00:00
|
|
|
@attr('string') namespace;
|
2023-05-05 20:25:21 +00:00
|
|
|
@attr('string') nodeID;
|
2020-06-10 13:49:16 +00:00
|
|
|
@attr('string') name;
|
|
|
|
@attr('string') taskGroupName;
|
|
|
|
@fragment('resources') resources;
|
|
|
|
@fragment('resources') allocatedResources;
|
|
|
|
@attr('number') jobVersion;
|
2018-07-19 20:31:39 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@attr('number') modifyIndex;
|
|
|
|
@attr('date') modifyTime;
|
2018-07-19 20:31:39 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@attr('number') createIndex;
|
|
|
|
@attr('date') createTime;
|
2017-09-19 14:47:10 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@attr('string') clientStatus;
|
|
|
|
@attr('string') desiredStatus;
|
2023-05-01 19:24:21 +00:00
|
|
|
@attr() desiredTransition;
|
[ui, feature] Job Page Redesign (#16932)
* [ui] Service job status panel (#16134)
* it begins
* Hacky demo enabled
* Still very hacky but seems deece
* Floor of at least 3 must be shown
* Width from on-high
* Other statuses considered
* More sensible allocTypes listing
* Beginnings of a legend
* Total number of allocs running now maps over job.groups
* Lintfix
* base the number of slots to hold open on actual tallies, which should never exceed totalAllocs
* Versions get yer versions here
* Versions lookin like versions
* Mirage fixup
* Adds Remaining as an alloc chart status and adds historical status option
* Get tests passing again by making job status static for a sec
* Historical status panel click actions moved into their own component class
* job detail tests plz chill
* Testing if percy is fickle
* Hyper-specfic on summary distribution bar identifier
* Perhaps the 2nd allocSummary item no longer exists with the more accurate afterCreate data
* UI Test eschewing the page pattern
* Bones of a new acceptance test
* Track width changes explicitly with window-resize
* testlintfix
* Alloc counting tests
* Alloc grouping test
* Alloc grouping with complex resizing
* Refined the list of showable statuses
* PR feedback addressed
* renamed allocation-row to allocation-status-row
* [ui, job status] Make panel status mode a queryParam (#16345)
* queryParam changing
* Test for QP in panel
* Adding @tracked to legacy controller
* Move the job of switching to Historical out to larger context
* integration test mock passed func
* [ui] Service job deployment status panel (#16383)
* A very fast and loose deployment panel
* Removing Unknown status from the panel
* Set up oldAllocs list in constructor, rather than as a getter/tracked var
* Small amount of template cleanup
* Refactored latest-deployment new logic back into panel.js
* Revert now-unused latest-deployment component
* margin bottom when ungrouped also
* Basic integration tests for job deployment status panel
* Updates complete alloc colour to green for new visualizations only (#16618)
* Updates complete alloc colour to green for new visualizations only
* Pale green instead of dark green for viz in general
* [ui] Job Deployment Status: History and Update Props (#16518)
* Deployment history wooooooo
* Styled deployment history
* Update Params
* lintfix
* Types and groups for updateParams
* Live-updating history
* Harden with types, error states, and pending states
* Refactor updateParams to use trigger component
* [ui] Deployment History search (#16608)
* Functioning searchbox
* Some nice animations for history items
* History search test
* Fixing up some old mirage conventions
* some a11y rule override to account for scss keyframes
* Split panel into deploying and steady components
* HandleError passed from job index
* gridified panel elements
* TotalAllocs added to deploying.js
* Width perc to px
* [ui] Splitting deployment allocs by status, health, and canary status (#16766)
* Initial attempt with lots of scratchpad work
* Style mods per UI discussion
* Fix canary overflow bug
* Dont show canary or health for steady/prev-alloc blocks
* Steady state
* Thanks Julie
* Fixes steady-state versions
* Legen, wait for it...
* Test fixes now that we have a minimum block size
* PR prep
* Shimmer effect on pending and unplaced allocs (#16801)
* Shimmer effect on pending and unplaced
* Dont show animation in the legend
* [ui, deployments] Linking allocblocks and legends to allocation / allocations index routes (#16821)
* Conditional link-to component and basic linking to allocations and allocation routes
* Job versions filter added to allocations index page
* Steady state legends link
* Legend links
* Badge count links for versions
* Fix: faded class on steady-state legend items
* version link now wont show completed ones
* Fix a11y violations with link labels
* Combining some template conditional logic
* [ui, deployments] Conversions on long nanosecond update params (#16882)
* Conversions on long nanosecond nums
* Early return in updateParamGroups comp prop
* [ui, deployments] Mirage Actively Deploying Job and Deployment Integration Tests (#16888)
* Start of deployment alloc test scaffolding
* Bit of test cleanup and canary for ungrouped allocs
* Flakey but more robust integrations for deployment panel
* De-flake acceptance tests and add an actively deploying job to mirage
* Jitter-less alloc status distribution removes my bad math
* bugfix caused by summary.desiredTotal non-null
* More interesting mirage active deployment alloc breakdown
* Further tests for previous-allocs row
* Previous alloc legend tests
* Percy snapshots added to integration test
* changelog
2023-04-25 02:45:39 +00:00
|
|
|
@attr() deploymentStatus;
|
|
|
|
|
|
|
|
get isCanary() {
|
|
|
|
return this.deploymentStatus?.Canary;
|
|
|
|
}
|
|
|
|
|
2023-06-19 16:06:18 +00:00
|
|
|
// deploymentStatus.Healthy can be true, false, or null. Null implies pending
|
[ui, feature] Job Page Redesign (#16932)
* [ui] Service job status panel (#16134)
* it begins
* Hacky demo enabled
* Still very hacky but seems deece
* Floor of at least 3 must be shown
* Width from on-high
* Other statuses considered
* More sensible allocTypes listing
* Beginnings of a legend
* Total number of allocs running now maps over job.groups
* Lintfix
* base the number of slots to hold open on actual tallies, which should never exceed totalAllocs
* Versions get yer versions here
* Versions lookin like versions
* Mirage fixup
* Adds Remaining as an alloc chart status and adds historical status option
* Get tests passing again by making job status static for a sec
* Historical status panel click actions moved into their own component class
* job detail tests plz chill
* Testing if percy is fickle
* Hyper-specfic on summary distribution bar identifier
* Perhaps the 2nd allocSummary item no longer exists with the more accurate afterCreate data
* UI Test eschewing the page pattern
* Bones of a new acceptance test
* Track width changes explicitly with window-resize
* testlintfix
* Alloc counting tests
* Alloc grouping test
* Alloc grouping with complex resizing
* Refined the list of showable statuses
* PR feedback addressed
* renamed allocation-row to allocation-status-row
* [ui, job status] Make panel status mode a queryParam (#16345)
* queryParam changing
* Test for QP in panel
* Adding @tracked to legacy controller
* Move the job of switching to Historical out to larger context
* integration test mock passed func
* [ui] Service job deployment status panel (#16383)
* A very fast and loose deployment panel
* Removing Unknown status from the panel
* Set up oldAllocs list in constructor, rather than as a getter/tracked var
* Small amount of template cleanup
* Refactored latest-deployment new logic back into panel.js
* Revert now-unused latest-deployment component
* margin bottom when ungrouped also
* Basic integration tests for job deployment status panel
* Updates complete alloc colour to green for new visualizations only (#16618)
* Updates complete alloc colour to green for new visualizations only
* Pale green instead of dark green for viz in general
* [ui] Job Deployment Status: History and Update Props (#16518)
* Deployment history wooooooo
* Styled deployment history
* Update Params
* lintfix
* Types and groups for updateParams
* Live-updating history
* Harden with types, error states, and pending states
* Refactor updateParams to use trigger component
* [ui] Deployment History search (#16608)
* Functioning searchbox
* Some nice animations for history items
* History search test
* Fixing up some old mirage conventions
* some a11y rule override to account for scss keyframes
* Split panel into deploying and steady components
* HandleError passed from job index
* gridified panel elements
* TotalAllocs added to deploying.js
* Width perc to px
* [ui] Splitting deployment allocs by status, health, and canary status (#16766)
* Initial attempt with lots of scratchpad work
* Style mods per UI discussion
* Fix canary overflow bug
* Dont show canary or health for steady/prev-alloc blocks
* Steady state
* Thanks Julie
* Fixes steady-state versions
* Legen, wait for it...
* Test fixes now that we have a minimum block size
* PR prep
* Shimmer effect on pending and unplaced allocs (#16801)
* Shimmer effect on pending and unplaced
* Dont show animation in the legend
* [ui, deployments] Linking allocblocks and legends to allocation / allocations index routes (#16821)
* Conditional link-to component and basic linking to allocations and allocation routes
* Job versions filter added to allocations index page
* Steady state legends link
* Legend links
* Badge count links for versions
* Fix: faded class on steady-state legend items
* version link now wont show completed ones
* Fix a11y violations with link labels
* Combining some template conditional logic
* [ui, deployments] Conversions on long nanosecond update params (#16882)
* Conversions on long nanosecond nums
* Early return in updateParamGroups comp prop
* [ui, deployments] Mirage Actively Deploying Job and Deployment Integration Tests (#16888)
* Start of deployment alloc test scaffolding
* Bit of test cleanup and canary for ungrouped allocs
* Flakey but more robust integrations for deployment panel
* De-flake acceptance tests and add an actively deploying job to mirage
* Jitter-less alloc status distribution removes my bad math
* bugfix caused by summary.desiredTotal non-null
* More interesting mirage active deployment alloc breakdown
* Further tests for previous-allocs row
* Previous alloc legend tests
* Percy snapshots added to integration test
* changelog
2023-04-25 02:45:39 +00:00
|
|
|
get isHealthy() {
|
|
|
|
return this.deploymentStatus?.Healthy;
|
|
|
|
}
|
2020-06-10 13:49:16 +00:00
|
|
|
|
2023-06-19 16:06:18 +00:00
|
|
|
get isUnhealthy() {
|
|
|
|
return this.deploymentStatus?.Healthy === false;
|
|
|
|
}
|
|
|
|
|
2023-05-01 19:24:21 +00:00
|
|
|
get willNotRestart() {
|
|
|
|
return this.clientStatus === 'failed' || this.clientStatus === 'lost';
|
|
|
|
}
|
|
|
|
|
|
|
|
get willNotReschedule() {
|
|
|
|
return (
|
|
|
|
this.willNotRestart &&
|
|
|
|
!this.get('nextAllocation.content') &&
|
|
|
|
!this.get('followUpEvaluation.content')
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
get hasBeenRescheduled() {
|
|
|
|
return this.get('followUpEvaluation.content');
|
|
|
|
}
|
|
|
|
|
|
|
|
get hasBeenRestarted() {
|
|
|
|
return this.states
|
|
|
|
.map((s) => s.events.content)
|
|
|
|
.flat()
|
|
|
|
.find((e) => e.type === 'Restarting');
|
|
|
|
}
|
|
|
|
|
2022-08-26 22:02:12 +00:00
|
|
|
@attr healthChecks;
|
|
|
|
|
|
|
|
async getServiceHealth() {
|
|
|
|
const data = await this.store.adapterFor('allocation').check(this);
|
|
|
|
|
|
|
|
// Compare Results
|
|
|
|
if (!isEqual(this.healthChecks, data)) {
|
|
|
|
this.set('healthChecks', data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 21:55:40 +00:00
|
|
|
@computed('')
|
|
|
|
get plainJobId() {
|
|
|
|
return JSON.parse(this.belongsTo('job').id())[0];
|
|
|
|
}
|
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@computed('clientStatus')
|
|
|
|
get statusIndex() {
|
2019-03-26 07:46:44 +00:00
|
|
|
return STATUS_ORDER[this.clientStatus] || 100;
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2017-09-19 14:47:10 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@equal('clientStatus', 'running') isRunning;
|
|
|
|
@attr('boolean') isMigrating;
|
2018-12-07 01:11:01 +00:00
|
|
|
|
2020-09-04 07:43:27 +00:00
|
|
|
@computed('clientStatus')
|
|
|
|
get isScheduled() {
|
2020-10-22 16:37:20 +00:00
|
|
|
return ['pending', 'running'].includes(this.clientStatus);
|
2020-09-04 07:43:27 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 04:28:40 +00:00
|
|
|
// An allocation model created from any allocation list response will be lacking
|
|
|
|
// many properties (some of which can always be null). This is an indicator that
|
|
|
|
// the allocation needs to be reloaded to get the complete allocation state.
|
2020-06-10 13:49:16 +00:00
|
|
|
@none('allocationTaskGroup') isPartial;
|
2020-05-13 04:28:40 +00:00
|
|
|
|
2018-04-25 22:50:15 +00:00
|
|
|
// When allocations are server-side rescheduled, a paper trail
|
|
|
|
// is left linking all reschedule attempts.
|
2020-06-10 13:49:16 +00:00
|
|
|
@belongsTo('allocation', { inverse: 'nextAllocation' }) previousAllocation;
|
|
|
|
@belongsTo('allocation', { inverse: 'previousAllocation' }) nextAllocation;
|
2018-05-02 18:21:50 +00:00
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
@hasMany('allocation', { inverse: 'preemptedByAllocation' })
|
|
|
|
preemptedAllocations;
|
|
|
|
@belongsTo('allocation', { inverse: 'preemptedAllocations' })
|
|
|
|
preemptedByAllocation;
|
2020-06-10 13:49:16 +00:00
|
|
|
@attr('boolean') wasPreempted;
|
2019-04-16 19:11:43 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@belongsTo('evaluation') followUpEvaluation;
|
2018-04-25 22:50:15 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@computed('clientStatus')
|
|
|
|
get statusClass() {
|
2017-10-30 21:16:08 +00:00
|
|
|
const classMap = {
|
|
|
|
pending: 'is-pending',
|
|
|
|
running: 'is-primary',
|
|
|
|
complete: 'is-complete',
|
|
|
|
failed: 'is-error',
|
|
|
|
lost: 'is-light',
|
2022-04-22 15:25:02 +00:00
|
|
|
unknown: 'is-unknown',
|
2017-10-30 21:16:08 +00:00
|
|
|
};
|
|
|
|
|
2019-03-26 07:46:44 +00:00
|
|
|
return classMap[this.clientStatus] || 'is-dark';
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2017-10-30 21:16:08 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@computed('jobVersion', 'job.version')
|
|
|
|
get isOld() {
|
2020-05-01 21:30:02 +00:00
|
|
|
return this.jobVersion !== this.get('job.version');
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2020-05-01 21:30:02 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@computed('isOld', 'jobTaskGroup', 'allocationTaskGroup')
|
|
|
|
get taskGroup() {
|
2020-05-01 21:30:02 +00:00
|
|
|
if (!this.isOld) return this.jobTaskGroup;
|
|
|
|
return this.allocationTaskGroup;
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2020-05-01 21:30:02 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@computed('taskGroupName', 'job.taskGroups.[]')
|
|
|
|
get jobTaskGroup() {
|
2017-09-19 14:47:10 +00:00
|
|
|
const taskGroups = this.get('job.taskGroups');
|
2019-03-26 07:46:44 +00:00
|
|
|
return taskGroups && taskGroups.findBy('name', this.taskGroupName);
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2017-09-19 14:47:10 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@fragment('task-group', { defaultValue: null }) allocationTaskGroup;
|
2020-05-01 21:30:02 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@computed('taskGroup.drivers.[]', 'node.unhealthyDriverNames.[]')
|
|
|
|
get unhealthyDrivers() {
|
2018-05-10 00:04:45 +00:00
|
|
|
const taskGroupUnhealthyDrivers = this.get('taskGroup.drivers');
|
|
|
|
const nodeUnhealthyDrivers = this.get('node.unhealthyDriverNames');
|
|
|
|
|
|
|
|
if (taskGroupUnhealthyDrivers && nodeUnhealthyDrivers) {
|
|
|
|
return intersection(taskGroupUnhealthyDrivers, nodeUnhealthyDrivers);
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2018-05-10 00:04:45 +00:00
|
|
|
|
2022-04-21 17:57:18 +00:00
|
|
|
// When per_alloc is set to true on a volume, the volumes are duplicated between active allocations.
|
|
|
|
// We differentiate them with a [#] suffix, inferred from a volume's allocation's name property.
|
|
|
|
@computed('name')
|
|
|
|
get volumeExtension() {
|
|
|
|
return this.name.substring(this.name.lastIndexOf('['));
|
|
|
|
}
|
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@fragmentArray('task-state') states;
|
|
|
|
@fragmentArray('reschedule-event') rescheduleEvents;
|
2018-05-02 18:21:50 +00:00
|
|
|
|
2020-06-10 13:49:16 +00:00
|
|
|
@computed('rescheduleEvents.length', 'nextAllocation')
|
|
|
|
get hasRescheduleEvents() {
|
2019-03-26 07:46:44 +00:00
|
|
|
return this.get('rescheduleEvents.length') > 0 || this.nextAllocation;
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
@computed(
|
|
|
|
'clientStatus',
|
|
|
|
'followUpEvaluation.content',
|
|
|
|
'nextAllocation.content'
|
|
|
|
)
|
2020-06-10 13:49:16 +00:00
|
|
|
get hasStoppedRescheduling() {
|
|
|
|
return (
|
|
|
|
!this.get('nextAllocation.content') &&
|
|
|
|
!this.get('followUpEvaluation.content') &&
|
|
|
|
this.clientStatus === 'failed'
|
|
|
|
);
|
|
|
|
}
|
2019-05-17 00:43:00 +00:00
|
|
|
|
|
|
|
stop() {
|
|
|
|
return this.store.adapterFor('allocation').stop(this);
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2019-05-17 00:43:00 +00:00
|
|
|
|
2019-05-20 22:27:20 +00:00
|
|
|
restart(taskName) {
|
|
|
|
return this.store.adapterFor('allocation').restart(this, taskName);
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2020-06-01 13:15:59 +00:00
|
|
|
|
2022-08-24 22:43:44 +00:00
|
|
|
restartAll() {
|
|
|
|
return this.store.adapterFor('allocation').restartAll(this);
|
|
|
|
}
|
|
|
|
|
2020-06-01 13:15:59 +00:00
|
|
|
ls(path) {
|
|
|
|
return this.store.adapterFor('allocation').ls(this, path);
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
2020-06-01 13:15:59 +00:00
|
|
|
|
|
|
|
stat(path) {
|
|
|
|
return this.store.adapterFor('allocation').stat(this, path);
|
2020-06-10 13:49:16 +00:00
|
|
|
}
|
|
|
|
}
|