mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 02:45:42 +03:00
Merge pull request #3769 from johncowen/f-componentize-placement-failures
Component-ize UI for placement failures
This commit is contained in:
40
ui/app/templates/components/placement-failure.hbs
Normal file
40
ui/app/templates/components/placement-failure.hbs
Normal file
@@ -0,0 +1,40 @@
|
||||
{{#if taskGroup.placementFailures}}
|
||||
{{#with taskGroup.placementFailures as |failures|}}
|
||||
<h3 class="title is-5" data-test-placement-failure-task-group>
|
||||
{{taskGroup.name}}
|
||||
<span class="badge is-light" data-test-placement-failure-coalesced-failures>{{inc failures.coalescedFailures}} unplaced</span>
|
||||
</h3>
|
||||
<ul class="simple-list">
|
||||
{{#if (eq failures.nodesEvaluated 0)}}
|
||||
<li data-test-placement-failure-no-evaluated-nodes>No nodes were eligible for evaluation</li>
|
||||
{{/if}}
|
||||
{{#each-in failures.nodesAvailable as |datacenter available|}}
|
||||
{{#if (eq available 0)}}
|
||||
<li data-test-placement-failure-no-nodes-available="{{datacenter}}">No nodes are available in datacenter {{datacenter}}</li>
|
||||
{{/if}}
|
||||
{{/each-in}}
|
||||
{{#each-in failures.classFiltered as |class count|}}
|
||||
<li data-test-placement-failure-class-filtered="{{class}}">Class {{class}} filtered {{count}} {{pluralize "node" count}}</li>
|
||||
{{/each-in}}
|
||||
{{#each-in failures.constraintFiltered as |constraint count|}}
|
||||
<li data-test-placement-failure-constraint-filtered="{{constraint}}">Constraint <code>{{constraint}}</code> filtered {{count}} {{pluralize "node" count}}</li>
|
||||
{{/each-in}}
|
||||
{{#if failures.nodesExhausted}}
|
||||
<li data-test-placement-failure-nodes-exhausted>Resources exhausted on {{failures.nodesExhausted}} {{pluralize "node" failures.nodesExhausted}}</li>
|
||||
{{/if}}
|
||||
{{#each-in failures.classExhausted as |class count|}}
|
||||
<li data-test-placement-failure-class-exhausted="{{class}}">Class {{class}} exhausted on {{count}} {{pluralize "node" count}}</li>
|
||||
{{/each-in}}
|
||||
{{#each-in failures.dimensionExhausted as |dimension count|}}
|
||||
<li data-test-placement-failure-dimension-exhausted="{{dimension}}">Dimension {{dimension}} exhausted on {{count}} {{pluralize "node" count}}</li>
|
||||
{{/each-in}}
|
||||
{{#each-in failures.quotaExhausted as |quota dimension|}}
|
||||
<li data-test-placement-failure-quota-exhausted="{{quota}}">Quota limit hit {{dimension}}</li>
|
||||
{{/each-in}}
|
||||
{{#each-in failures.scores as |name score|}}
|
||||
<li data-test-placement-failure-scores="{{name}}">Score {{name}} = {{score}}</li>
|
||||
{{/each-in}}
|
||||
</ul>
|
||||
{{/with}}
|
||||
{{/if}}
|
||||
|
||||
@@ -56,45 +56,7 @@
|
||||
</div>
|
||||
<div class="boxed-section-body">
|
||||
{{#each model.taskGroups as |taskGroup|}}
|
||||
{{#if taskGroup.placementFailures}}
|
||||
{{#with taskGroup.placementFailures as |failures|}}
|
||||
<h3 class="title is-5" data-test-placement-failure-task-group>
|
||||
{{taskGroup.name}}
|
||||
<span class="badge is-light">{{inc failures.coalescedFailures}} unplaced</span>
|
||||
</h3>
|
||||
<ul class="simple-list">
|
||||
{{#if (eq failures.nodesEvaluated 0)}}
|
||||
<li>No nodes were eligible for evaluation</li>
|
||||
{{/if}}
|
||||
{{#each-in failures.nodesAvailable as |datacenter available|}}
|
||||
{{#if (eq available 0)}}
|
||||
<li>No nodes are available in datacenter {{datacenter}}</li>
|
||||
{{/if}}
|
||||
{{/each-in}}
|
||||
{{#each-in failures.classFiltered as |class count|}}
|
||||
<li>Class {{class}} filtered {{count}} {{pluralize "node" count}}</li>
|
||||
{{/each-in}}
|
||||
{{#each-in failures.constraintFiltered as |constraint count|}}
|
||||
<li>Constraint <code>{{constraint}}</code> filtered {{count}} {{pluralize "node" count}}</li>
|
||||
{{/each-in}}
|
||||
{{#if failures.nodesExhausted}}
|
||||
<li>Resources exhausted on {{failures.nodesExhausted}} {{pluralize "node" failures.nodesExhausted}}</li>
|
||||
{{/if}}
|
||||
{{#each-in failures.classExhausted as |class count|}}
|
||||
<li>Class {{class}} exhausted on {{count}} {{pluralize "node" count}}</li>
|
||||
{{/each-in}}
|
||||
{{#each-in failures.dimensionExhausted as |dimension count|}}
|
||||
<li>Dimension {{dimension}} exhausted on {{count}} {{pluralize "node" count}}</li>
|
||||
{{/each-in}}
|
||||
{{#each-in failures.quotaExhausted as |quota dimension|}}
|
||||
<li>Quota limit hit {{dimension}}</li>
|
||||
{{/each-in}}
|
||||
{{#each-in failures.scores as |name score|}}
|
||||
<li>Score {{name}} = {{score}}</li>
|
||||
{{/each-in}}
|
||||
</ul>
|
||||
{{/with}}
|
||||
{{/if}}
|
||||
{{placement-failure taskGroup=taskGroup}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { findAll, find } from 'ember-native-dom-helpers';
|
||||
import { test, moduleForComponent } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import cleanWhitespace from '../utils/clean-whitespace';
|
||||
|
||||
moduleForComponent('job-diff', 'Integration | Component | job diff', {
|
||||
integration: true,
|
||||
@@ -192,10 +193,3 @@ function field(name, type, newVal, oldVal) {
|
||||
Name: name,
|
||||
};
|
||||
}
|
||||
|
||||
function cleanWhitespace(string) {
|
||||
return string
|
||||
.replace(/\n/g, '')
|
||||
.replace(/ +/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
144
ui/tests/integration/placement-failure-test.js
Normal file
144
ui/tests/integration/placement-failure-test.js
Normal file
@@ -0,0 +1,144 @@
|
||||
import { find, findAll } from 'ember-native-dom-helpers';
|
||||
import { test, moduleForComponent } from 'ember-qunit';
|
||||
import { assign } from '@ember/polyfills';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import cleanWhitespace from '../utils/clean-whitespace';
|
||||
|
||||
moduleForComponent('placement-failure', 'Integration | Component | placement failures', {
|
||||
integration: true,
|
||||
});
|
||||
|
||||
const commonTemplate = hbs`
|
||||
{{placement-failure taskGroup=taskGroup}}
|
||||
`;
|
||||
|
||||
test('should render the placement failure (basic render)', function(assert) {
|
||||
const name = 'Placement Failure';
|
||||
const failures = 11;
|
||||
this.set(
|
||||
'taskGroup',
|
||||
createFixture(
|
||||
{
|
||||
coalescedFailures: failures - 1
|
||||
},
|
||||
name
|
||||
)
|
||||
);
|
||||
|
||||
this.render(commonTemplate);
|
||||
|
||||
assert.equal(
|
||||
cleanWhitespace(find('[data-test-placement-failure-task-group]').firstChild.wholeText),
|
||||
name,
|
||||
'Title is rendered with the name of the placement failure'
|
||||
);
|
||||
assert.equal(
|
||||
parseInt(find('[data-test-placement-failure-coalesced-failures]').textContent),
|
||||
failures,
|
||||
'Title is rendered correctly with a count of unplaced'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-no-evaluated-nodes]').length,
|
||||
1,
|
||||
'No evaluated nodes message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-no-nodes-available]').length,
|
||||
1,
|
||||
'No nodes in datacenter message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-class-filtered]').length,
|
||||
1,
|
||||
'Class filtered message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-constraint-filtered]').length,
|
||||
1,
|
||||
'Constraint filtered message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-nodes-exhausted]').length,
|
||||
1,
|
||||
'Node exhausted message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-class-exhausted]').length,
|
||||
1,
|
||||
'Class exhausted message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-dimension-exhausted]').length,
|
||||
1,
|
||||
'Dimension exhausted message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-quota-exhausted]').length,
|
||||
1,
|
||||
'Quota exhausted message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-scores]').length,
|
||||
1,
|
||||
'Scores message shown'
|
||||
);
|
||||
});
|
||||
|
||||
test('should render correctly when a node is not evaluated', function(assert) {
|
||||
this.set(
|
||||
'taskGroup',
|
||||
createFixture(
|
||||
{
|
||||
nodesEvaluated: 1,
|
||||
nodesExhausted: 0
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
this.render(commonTemplate);
|
||||
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-no-evaluated-nodes]').length,
|
||||
0,
|
||||
'No evaluated nodes message shown'
|
||||
);
|
||||
assert.equal(
|
||||
findAll('[data-test-placement-failure-nodes-exhausted]').length,
|
||||
0,
|
||||
'Nodes exhausted message NOT shown when there are no nodes exausted'
|
||||
);
|
||||
});
|
||||
|
||||
function createFixture(obj = {}, name = 'Placement Failure') {
|
||||
return {
|
||||
name: name,
|
||||
placementFailures: assign({
|
||||
coalescedFailures: 10,
|
||||
nodesEvaluated: 0,
|
||||
nodesAvailable: {
|
||||
datacenter: 0,
|
||||
},
|
||||
classFiltered: {
|
||||
filtered: 1,
|
||||
},
|
||||
constraintFiltered: {
|
||||
'prop = val': 1,
|
||||
},
|
||||
nodesExhausted: 3,
|
||||
classExhausted: {
|
||||
class: 3,
|
||||
},
|
||||
dimensionExhausted: {
|
||||
iops: 3,
|
||||
},
|
||||
quotaExhausted: {
|
||||
quota: 'dimension',
|
||||
},
|
||||
scores: {
|
||||
name: 3,
|
||||
},
|
||||
},
|
||||
obj
|
||||
)
|
||||
};
|
||||
}
|
||||
8
ui/tests/utils/clean-whitespace.js
Normal file
8
ui/tests/utils/clean-whitespace.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// cleans whitespace from a string, for example for cleaning
|
||||
// textContent in DOM nodes with indentation
|
||||
export default function cleanWhitespace(string) {
|
||||
return string
|
||||
.replace(/\n/g, '')
|
||||
.replace(/ +/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
Reference in New Issue
Block a user