diff --git a/ui/app/adapters/job-scale.js b/ui/app/adapters/job-scale.js new file mode 100644 index 000000000..8cca86df7 --- /dev/null +++ b/ui/app/adapters/job-scale.js @@ -0,0 +1,3 @@ +import WatchableNamespaceIDs from './watchable-namespace-ids'; + +export default class JobScaleAdapter extends WatchableNamespaceIDs {} diff --git a/ui/app/models/job-scale.js b/ui/app/models/job-scale.js new file mode 100644 index 000000000..54424d9b6 --- /dev/null +++ b/ui/app/models/job-scale.js @@ -0,0 +1,11 @@ +import Model from 'ember-data/model'; +import { belongsTo } from 'ember-data/relationships'; +import { fragmentArray } from 'ember-data-model-fragments/attributes'; +import classic from 'ember-classic-decorator'; + +@classic +export default class JobSummary extends Model { + @belongsTo('job') job; + + @fragmentArray('task-group-scale') taskGroupScales; +} diff --git a/ui/app/models/job.js b/ui/app/models/job.js index 154fc07b1..86717ea0a 100644 --- a/ui/app/models/job.js +++ b/ui/app/models/job.js @@ -119,6 +119,7 @@ export default class Job extends Model { @hasMany('deployments') deployments; @hasMany('evaluations') evaluations; @belongsTo('namespace') namespace; + @belongsTo('job-scale') scaleState; @computed('taskGroups.@each.drivers') get drivers() { diff --git a/ui/app/models/scale-event.js b/ui/app/models/scale-event.js new file mode 100644 index 000000000..ecab7bc46 --- /dev/null +++ b/ui/app/models/scale-event.js @@ -0,0 +1,18 @@ +import Fragment from 'ember-data-model-fragments/fragment'; +import attr from 'ember-data/attr'; +import { fragmentOwner } from 'ember-data-model-fragments/attributes'; + +export default class ScaleEvent extends Fragment { + @fragmentOwner() taskGroupScale; + + @attr('number') count; + @attr('number') previousCount; + @attr('boolean') error; + @attr('string') evalId; + + @attr('date') time; + @attr('number') timeNanos; + + @attr('string') message; + @attr() meta; +} diff --git a/ui/app/models/task-group-scale.js b/ui/app/models/task-group-scale.js new file mode 100644 index 000000000..83fa05d2e --- /dev/null +++ b/ui/app/models/task-group-scale.js @@ -0,0 +1,17 @@ +import Fragment from 'ember-data-model-fragments/fragment'; +import attr from 'ember-data/attr'; +import { fragmentOwner, fragmentArray } from 'ember-data-model-fragments/attributes'; + +export default class TaskGroupScale extends Fragment { + @fragmentOwner() jobScale; + + @attr('string') name; + + @attr('number') desired; + @attr('number') placed; + @attr('number') running; + @attr('number') healthy; + @attr('number') unhealthy; + + @fragmentArray('scale-event') events; +} diff --git a/ui/app/models/task-group.js b/ui/app/models/task-group.js index 4926f0aff..e92c2c82c 100644 --- a/ui/app/models/task-group.js +++ b/ui/app/models/task-group.js @@ -54,6 +54,11 @@ export default class TaskGroup extends Fragment { return maybe(this.get('job.taskGroupSummaries')).findBy('name', this.name); } + @computed('job.scaleState.taskGroupScales.[]') + get scaleState() { + return maybe(this.get('job.scaleState.taskGroupScales')).findBy('name', this.name); + } + scale(count, reason) { return this.job.scale(this.name, count, reason); } diff --git a/ui/app/serializers/job-scale.js b/ui/app/serializers/job-scale.js new file mode 100644 index 000000000..b0ab04d87 --- /dev/null +++ b/ui/app/serializers/job-scale.js @@ -0,0 +1,19 @@ +import { assign } from '@ember/polyfills'; +import ApplicationSerializer from './application'; + +export default class JobScale extends ApplicationSerializer { + normalize(modelClass, hash) { + // Transform the map-based TaskGroups object into an array-based + // TaskGroupScale fragment list + hash.PlainJobId = hash.JobID; + hash.ID = JSON.stringify([hash.JobID, hash.Namespace || 'default']); + hash.JobID = hash.ID; + + const taskGroups = hash.TaskGroups || {}; + hash.TaskGroupScales = Object.keys(taskGroups).map(key => { + return assign(taskGroups[key], { Name: key }); + }); + + return super.normalize(modelClass, hash); + } +} diff --git a/ui/app/serializers/job.js b/ui/app/serializers/job.js index ded935c00..7273141d0 100644 --- a/ui/app/serializers/job.js +++ b/ui/app/serializers/job.js @@ -84,6 +84,11 @@ export default class JobSerializer extends ApplicationSerializer { related: buildURL(`${jobURL}/evaluations`, { namespace }), }, }, + scale: { + links: { + related: buildURL(`${jobURL}/scale`, { namespace }), + }, + }, }); } } diff --git a/ui/app/serializers/scale-event.js b/ui/app/serializers/scale-event.js new file mode 100644 index 000000000..758ec3040 --- /dev/null +++ b/ui/app/serializers/scale-event.js @@ -0,0 +1,10 @@ +import ApplicationSerializer from './application'; + +export default class ScaleEventSerializer extends ApplicationSerializer { + normalize(typeHash, hash) { + hash.TimeNanos = hash.Time % 1000000; + hash.Time = Math.floor(hash.Time / 1000000); + + return super.normalize(typeHash, hash); + } +}