Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/27846.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
ui: The topology page now also shows reserved resources (CPU and memory) of every node using an orange bar at the end
```
6 changes: 6 additions & 0 deletions ui/app/components/svg-patterns.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
<image xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+CiAgPHJlY3Qgd2lkdGg9JzEwJyBoZWlnaHQ9JzEwJyBmaWxsPSd3aGl0ZScvPgogIDxwYXRoIGQ9J00tMSwxIGwyLC0yCiAgICAgICAgICAgTTAsMTAgbDEwLC0xMAogICAgICAgICAgIE05LDExIGwyLC0yJyBzdHJva2U9J2JsYWNrJyBzdHJva2Utd2lkdGg9JzMnLz4KPC9zdmc+" x="0" y="0" width="10" height="10"></image>
</pattern>

{{! Evenly sized diagonal stripes in orange}}
<pattern id="diagonal-stripe-orange" patternUnits="userSpaceOnUse" width="10" height="10">
<rect width="10" height="10" fill="#fcc187"/>
<path d="M-1,1 l2,-2 M0,10 l10,-10 M9,11 l2,-2" stroke="#fa8e23" stroke-width="3"/>
</pattern>

<linearGradient class="das-gradient" id="recommendation-chart-decrease-gradient" x2="100%" y2="0">
<stop offset="0%" stop-color="var(--full-color)" />
<stop offset="100%" stop-color="var(--faint-color)" />
Expand Down
16 changes: 16 additions & 0 deletions ui/app/components/topo-viz.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
@onAllocationSelect={{this.associateAllocations}}
@onAllocationFocus={{this.showTooltip}}
@onAllocationBlur={{this.hideTooltip}}
@onReservedFocus={{this.showReservedTooltip}}
@onNodeSelect={{this.showNodeDetails}} />
</FlexMasonry>

Expand Down Expand Up @@ -50,6 +51,21 @@
{{/let}}
</div>

<div class="chart-tooltip is-absolute {{if this.highlightReserved "active" "inactive"}}" style={{this.tooltipStyle}}>
{{#let this.highlightReserved as |reserved|}}
<ol class="is-static">
<li>
<span class="label">Memory</span>
<span class="value">{{format-scheduled-bytes reserved.memory start="MiB"}} reserved</span>
</li>
<li>
<span class="label">CPU</span>
<span class="value">{{format-scheduled-hertz reserved.cpu}} reserved</span>
</li>
</ol>
{{/let}}
</div>

{{#if this.activeAllocation}}
<svg data-test-allocation-associations class="chart topo-viz-edges" {{window-resize this.resizeEdges}}>
<g transform="translate({{this.edgeOffset.x}},{{this.edgeOffset.y}})">
Expand Down
13 changes: 13 additions & 0 deletions ui/app/components/topo-viz.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default class TopoViz extends Component {
@tracked viewportColumns = 2;

@tracked highlightAllocation = null;
@tracked highlightReserved = null;
@tracked tooltipProps = {};

@styleStringProperty('tooltipProps') tooltipStyle;
Expand Down Expand Up @@ -192,6 +193,17 @@ export default class TopoViz extends Component {
@action showTooltip(allocation, element) {
const bbox = element.getBoundingClientRect();
this.highlightAllocation = allocation;
this.highlightReserved = null;
this.tooltipProps = {
left: window.scrollX + bbox.left + bbox.width / 2,
top: window.scrollY + bbox.top,
};
}

@action showReservedTooltip(reserved, element) {
const bbox = element.getBoundingClientRect();
this.highlightReserved = reserved;
this.highlightAllocation = null;
this.tooltipProps = {
left: window.scrollX + bbox.left + bbox.width / 2,
top: window.scrollY + bbox.top,
Expand All @@ -200,6 +212,7 @@ export default class TopoViz extends Component {

@action hideTooltip() {
this.highlightAllocation = null;
this.highlightReserved = null;
}

@action
Expand Down
1 change: 1 addition & 0 deletions ui/app/components/topo-viz/datacenter.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
@onAllocationSelect={{@onAllocationSelect}}
@onAllocationFocus={{@onAllocationFocus}}
@onAllocationBlur={{@onAllocationBlur}}
@onReservedFocus={{@onReservedFocus}}
@onNodeSelect={{@onNodeSelect}} />
</FlexMasonry>
</div>
Expand Down
40 changes: 40 additions & 0 deletions ui/app/components/topo-viz/node.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,25 @@
width="{{this.data.memoryRemainder.width}}px"
height="{{this.height}}px" />
{{/if}}
{{#if this.data.memoryReserved}}
<g
data-test-reserved-memory
class="reserved-segment"
clip-path="url(#{{this.maskId}})"
{{on "mouseenter" this.highlightReserved}}
{{on "mouseleave" this.allocationBlur}}>
<rect
class="layer-0"
x="{{this.data.memoryReserved.x}}px"
width="{{this.data.memoryReserved.width}}px"
height="{{this.height}}px" />
<rect
class="layer-1"
x="{{this.data.memoryReserved.x}}px"
width="{{this.data.memoryReserved.width}}px"
height="{{this.height}}px" />
</g>
{{/if}}
{{#each this.data.memory key="allocation.id" as |memory|}}
<g
data-test-memory-rect="{{memory.allocation.allocation.id}}"
Expand Down Expand Up @@ -120,6 +139,27 @@
width="{{this.data.cpuRemainder.width}}px"
height="{{this.height}}px" />
{{/if}}
{{#if this.data.cpuReserved}}
<g
data-test-reserved-cpu
class="reserved-segment"
clip-path="url(#{{this.maskId}})"
{{on "mouseenter" this.highlightReserved}}
{{on "mouseleave" this.allocationBlur}}>
<rect
class="layer-0"
x="{{this.data.cpuReserved.x}}px"
y="{{this.yOffset}}px"
width="{{this.data.cpuReserved.width}}px"
height="{{this.height}}px" />
<rect
class="layer-1"
x="{{this.data.cpuReserved.x}}px"
y="{{this.yOffset}}px"
width="{{this.data.cpuReserved.width}}px"
height="{{this.height}}px" />
</g>
{{/if}}
{{#each this.data.cpu key="allocation.id" as |cpu|}}
<g
data-test-cpu-rect="{{cpu.allocation.allocation.id}}"
Expand Down
46 changes: 44 additions & 2 deletions ui/app/components/topo-viz/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ export default class TopoVizNode extends Component {
this.args.onAllocationFocus(allocation, target);
}

@action
highlightReserved({ target }) {
this.args.onReservedFocus &&
this.args.onReservedFocus(
{
cpu: this.args.node.node?.reserved?.cpu,
memory: this.args.node.node?.reserved?.memory,
},
target
);
}

@action
allocationBlur() {
this.args.onAllocationBlur && this.args.onAllocationBlur();
Expand Down Expand Up @@ -177,20 +189,50 @@ export default class TopoVizNode extends Component {
memoryOffset += memoryPercent;
}

const cpuReservedRaw = this.args.node.node?.reserved?.cpu;
const memoryReservedRaw = this.args.node.node?.reserved?.memory;

const cpuReservedPercent = cpuReservedRaw
? cpuReservedRaw / this.args.node.cpu
: 0;
const memoryReservedPercent = memoryReservedRaw
? memoryReservedRaw / this.args.node.memory
: 0;

const cpuRemainder = {
x: cpuOffset * width + 0.5,
width: Math.max(width - cpuOffset * width, 0),
width: Math.max((1 - cpuReservedPercent) * width - cpuOffset * width, 0),
};
const memoryRemainder = {
x: memoryOffset * width + 0.5,
width: Math.max(width - memoryOffset * width, 0),
width: Math.max(
(1 - memoryReservedPercent) * width - memoryOffset * width,
0
),
};

const cpuReserved =
cpuReservedPercent > 0
? {
x: (1 - cpuReservedPercent) * width + 0.5,
width: Math.max(cpuReservedPercent * width - 0.5, 0),
}
: null;
const memoryReserved =
memoryReservedPercent > 0
? {
x: (1 - memoryReservedPercent) * width + 0.5,
width: Math.max(memoryReservedPercent * width - 0.5, 0),
}
: null;

return {
cpu,
memory,
cpuRemainder,
memoryRemainder,
cpuReserved,
memoryReserved,
cpuLabel: { x: -this.paddingLeft / 2, y: this.height / 2 + this.yOffset },
memoryLabel: { x: -this.paddingLeft / 2, y: this.height / 2 },
};
Expand Down
11 changes: 11 additions & 0 deletions ui/app/styles/charts/colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@ $canceled: $dark;
);
}

&.reserved {
$reserved-base: lighten($orange, 20%);
background: repeating-linear-gradient(
-45deg,
$reserved-base,
$reserved-base 3px,
darken($reserved-base, 20%) 3px,
darken($reserved-base, 20%) 6px
);
}

&.running {
background: $running;
}
Expand Down
10 changes: 10 additions & 0 deletions ui/app/styles/charts/topo-viz-node.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@
fill: lighten($grey-lighter, 5%);
}

.reserved-segment {
rect.layer-0 {
fill: #fcc187;
}

rect.layer-1 {
fill: url(#diagonal-stripe-orange);
}
}

.dimensions.is-active {
.bar {
opacity: 0.2;
Expand Down
8 changes: 8 additions & 0 deletions ui/app/templates/topology.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@
Starting
</dd>
</div>
<div class="legend-term">
<dt>
<span class="color-swatch is-wide reserved" title="Reserved"></span>
</dt>
<dd>
Reserved
</dd>
</div>
</dl>
</div>
</div>
Expand Down
14 changes: 14 additions & 0 deletions ui/mirage/scenarios/topo.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ export function topoSmall(server) {
nodeResources: genResources(3000, 5192),
});

// Add one node with reserved resources to show reserved node in topology view
server.createList('node', 1, 'reserved', {
datacenter: 'dc1',
status: 'ready',
nodeResources: genResources(8000, 12192),
});

const jobResources = [
['M: 2560, C: 150'],
['M: 128, C: 400'],
Expand Down Expand Up @@ -80,6 +87,13 @@ export function topoMedium(server) {
nodeResources: genResources(8000, 12192),
});

// Add some nodes with reserved resources to show reserved node in topology view
server.createList('node', 3, 'reserved', {
datacenter: 'us-east-1',
status: 'ready',
nodeResources: genResources(8000, 12192),
});

const jobResources = [
['M: 2560, C: 150'],
['M: 128, C: 400'],
Expand Down
40 changes: 40 additions & 0 deletions ui/tests/integration/components/topo-viz/node-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -443,4 +443,44 @@ module('Integration | Component | TopoViz::Node', function (hooks) {
await render(commonTemplate);
assert.equal(TopoVizNode.emptyMessage, 'Empty Client');
});

test('when the node has reserved resources, reserved segments are shown in the CPU and memory bars', async function (assert) {
const node = nodeGen('Node One', 'dc1', 1000, 1000);
node.node.reserved = { cpu: 100, memory: 200 };

this.setProperties(
props({
node: {
...node,
allocations: [allocGen(node, 100, 100)],
},
})
);

await render(commonTemplate);

assert.ok(
TopoVizNode.reservedMemoryRect,
'reserved memory segment is rendered'
);
assert.ok(TopoVizNode.reservedCpuRect, 'reserved cpu segment is rendered');
});

test('when the node has no reserved resources, no reserved segments are shown', async function (assert) {
const node = nodeGen('Node One', 'dc1', 1000, 1000);

this.setProperties(
props({
node: {
...node,
allocations: [allocGen(node, 100, 100)],
},
})
);

await render(commonTemplate);

assert.notOk(TopoVizNode.reservedMemoryRect, 'no reserved memory segment');
assert.notOk(TopoVizNode.reservedCpuRect, 'no reserved cpu segment');
});
});
3 changes: 3 additions & 0 deletions ui/tests/pages/components/topo-viz/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ export default (scope) => ({
id: attribute('data-test-cpu-rect'),
}),

reservedMemoryRect: isPresent('[data-test-reserved-memory]'),
reservedCpuRect: isPresent('[data-test-reserved-cpu]'),

mouseout: triggerable('mouseout', '[data-test-topo-node-svg]'),

emptyMessage: text('[data-test-empty-message]'),
Expand Down
Loading