diff --git a/CHANGELOG.md b/CHANGELOG.md index 707e57a7540..05fe254334e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ IMPROVEMENTS: * networking: Added support for interpolating host network names with node attributes. [[GH-10196](https://github.com/hashicorp/nomad/issues/10196)] * nomad/structs: Removed deprecated Node.Drain field, added API extensions to restore it [[GH-10202](https://github.com/hashicorp/nomad/issues/10202)] * ui: Added a job reversion button [[GH-10336](https://github.com/hashicorp/nomad/pull/10336)] + * ui: Added memory maximum to task group ribbon [[GH-10459](https://github.com/hashicorp/nomad/pull/10459)] * ui: Updated global search to use fuzzy search API [[GH-10412](https://github.com/hashicorp/nomad/pull/10412)] BUG FIXES: diff --git a/ui/app/models/resources.js b/ui/app/models/resources.js index 1ac7bfad9bd..5e3fbce00d0 100644 --- a/ui/app/models/resources.js +++ b/ui/app/models/resources.js @@ -5,6 +5,7 @@ import { fragmentArray } from 'ember-data-model-fragments/attributes'; export default class Resources extends Fragment { @attr('number') cpu; @attr('number') memory; + @attr('number') memoryMax; @attr('number') disk; @attr('number') iops; @fragmentArray('network', { defaultValue: () => [] }) networks; diff --git a/ui/app/models/task-group.js b/ui/app/models/task-group.js index 49d53a23154..14475e7315e 100644 --- a/ui/app/models/task-group.js +++ b/ui/app/models/task-group.js @@ -36,6 +36,13 @@ export default class TaskGroup extends Fragment { @sumAggregation('tasks', 'reservedMemory') reservedMemory; @sumAggregation('tasks', 'reservedDisk') reservedDisk; + @computed('tasks.@each.{reservedMemory,reservedMemoryMax}') + get reservedMemoryMax() { + return this.get('tasks') + .map(t => t.get('reservedMemoryMax') || t.get('reservedMemory')) + .reduce((sum, count) => sum + count, 0); + } + @attr('number') reservedEphemeralDisk; @computed('job.latestFailureEvaluation.failedTGAllocs.[]', 'name') diff --git a/ui/app/models/task.js b/ui/app/models/task.js index b5f637da577..3dbb818f79e 100644 --- a/ui/app/models/task.js +++ b/ui/app/models/task.js @@ -30,6 +30,7 @@ export default class Task extends Fragment { } @attr('number') reservedMemory; + @attr('number') reservedMemoryMax; @attr('number') reservedCPU; @attr('number') reservedDisk; @attr('number') reservedEphemeralDisk; diff --git a/ui/app/serializers/task.js b/ui/app/serializers/task.js index ea09c5dcf62..2ed5dbe9bae 100644 --- a/ui/app/serializers/task.js +++ b/ui/app/serializers/task.js @@ -6,6 +6,7 @@ export default class Task extends ApplicationSerializer { const resources = hash.Resources; if (resources) { hash.ReservedMemory = resources.MemoryMB; + hash.ReservedMemoryMax = resources.MemoryMaxMB; hash.ReservedCPU = resources.CPU; hash.ReservedDisk = resources.DiskMB; hash.ReservedEphemeralDisk = hash.EphemeralDisk.SizeMB; diff --git a/ui/app/templates/jobs/job/task-group.hbs b/ui/app/templates/jobs/job/task-group.hbs index 934368824bb..e1f7fd5c069 100644 --- a/ui/app/templates/jobs/job/task-group.hbs +++ b/ui/app/templates/jobs/job/task-group.hbs @@ -31,7 +31,13 @@ # Tasks {{this.model.tasks.length}} Reserved CPU {{format-scheduled-hertz this.model.reservedCPU}} - Reserved Memory {{format-scheduled-bytes this.model.reservedMemory start="MiB"}} + + Reserved Memory + {{format-scheduled-bytes this.model.reservedMemory start="MiB"}} + {{#if (gt this.model.reservedMemoryMax this.model.reservedMemory)}} + ({{format-scheduled-bytes this.model.reservedMemoryMax start="MiB"}} Max) + {{/if}} + Reserved Disk {{format-scheduled-bytes this.model.reservedEphemeralDisk start="MiB"}} {{#if this.model.scaling}} Count Range diff --git a/ui/mirage/common.js b/ui/mirage/common.js index cac53cdb0ac..9646a60f691 100644 --- a/ui/mirage/common.js +++ b/ui/mirage/common.js @@ -24,7 +24,7 @@ export const HOSTS = provide(100, () => { export const STORAGE_PROVIDERS = ['ebs', 'zfs', 'nfs', 'cow', 'moo']; export function generateResources(options = {}) { - return { + const resources = { Cpu: { CpuShares: options.CPU || faker.helpers.randomize(CPU_RESERVATIONS), }, @@ -37,6 +37,15 @@ export function generateResources(options = {}) { Networks: generateNetworks(options.networks), Ports: generatePorts(options.networks), }; + + if (faker.random.boolean()) { + const higherMemoryReservations = MEMORY_RESERVATIONS.filter(mb => mb > resources.Memory.MemoryMB); + resources.Memory.MemoryMaxMB = faker.helpers.randomize(higherMemoryReservations) || resources.Memory.MemoryMB + 1; + } else { + resources.Memory.MemoryMaxMB = 0; + } + + return resources; } export function generateNetworks(options = {}) { diff --git a/ui/mirage/factories/task.js b/ui/mirage/factories/task.js index 88c5b23cff4..4b79820e3c1 100644 --- a/ui/mirage/factories/task.js +++ b/ui/mirage/factories/task.js @@ -26,6 +26,7 @@ export default Factory.extend({ return { CPU: resources.Cpu.CpuShares, MemoryMB: resources.Memory.MemoryMB, + MemoryMaxMB: resources.Memory.MemoryMaxMB, DiskMB: resources.Disk.DiskMB, }; }, diff --git a/ui/tests/acceptance/task-group-detail-test.js b/ui/tests/acceptance/task-group-detail-test.js index e097b27a9d3..a56c8874710 100644 --- a/ui/tests/acceptance/task-group-detail-test.js +++ b/ui/tests/acceptance/task-group-detail-test.js @@ -82,6 +82,7 @@ module('Acceptance | task group detail', function(hooks) { test('/jobs/:id/:task-group should list high-level metrics for the allocation', async function(assert) { const totalCPU = tasks.mapBy('resources.CPU').reduce(sum, 0); const totalMemory = tasks.mapBy('resources.MemoryMB').reduce(sum, 0); + const totalMemoryMax = tasks.map(t => t.resources.MemoryMaxMB || t.resources.MemoryMB).reduce(sum, 0); const totalDisk = taskGroup.ephemeralDisk.SizeMB; await TaskGroup.visit({ id: job.id, name: taskGroup.name }); @@ -92,9 +93,16 @@ module('Acceptance | task group detail', function(hooks) { `Reserved CPU ${formatScheduledHertz(totalCPU, 'MHz')}`, 'Aggregated CPU reservation for all tasks' ); + + let totalMemoryMaxAddendum = ''; + + if (totalMemoryMax > totalMemory) { + totalMemoryMaxAddendum = ` (${formatScheduledBytes(totalMemoryMax, 'MiB')} Max)`; + } + assert.equal( TaskGroup.mem, - `Reserved Memory ${formatScheduledBytes(totalMemory, 'MiB')}`, + `Reserved Memory ${formatScheduledBytes(totalMemory, 'MiB')}${totalMemoryMaxAddendum}`, 'Aggregated Memory reservation for all tasks' ); assert.equal(