[ui] Disconnected Clients: "Unknown" allocations in the UI (#12544)

* Unknown status for allocations accounted for

* Canary string removed

* Test cleanup

* Generate unknown in mirage

* aacidentally oovervoowled

* Update ui/app/components/allocation-status-bar.js

Co-authored-by: Derek Strickland <1111455+DerekStrickland@users.noreply.github.com>

* Disconnected state on job status in client

* Renaming Disconnected to Unknown in the job-status-in-client

* Unknown accounted for on job rows filtering and testsfix

* Adding lostAllocs as a computed dependency

* Unknown client status within acceptance test

* Swatches updated and PR comments addressed

* Unknown and disconnected added to test fixtures

Co-authored-by: Derek Strickland <1111455+DerekStrickland@users.noreply.github.com>
This commit is contained in:
Phil Renaud
2022-04-22 11:25:02 -04:00
committed by GitHub
parent 0abe5a6c79
commit cabe05705c
27 changed files with 132 additions and 22 deletions

View File

@@ -25,7 +25,7 @@ export default class AllocationStatusBar extends DistributionBar {
}
@computed(
'allocationContainer.{queuedAllocs,completeAllocs,failedAllocs,runningAllocs,startingAllocs}',
'allocationContainer.{queuedAllocs,completeAllocs,failedAllocs,runningAllocs,startingAllocs,lostAllocs,unknownAllocs}',
'job.namespace'
)
get data() {
@@ -39,7 +39,8 @@ export default class AllocationStatusBar extends DistributionBar {
'failedAllocs',
'runningAllocs',
'startingAllocs',
'lostAllocs'
'lostAllocs',
'unknownAllocs'
);
return [
{
@@ -67,6 +68,13 @@ export default class AllocationStatusBar extends DistributionBar {
className: 'complete',
legendLink: this.generateLegendLink(this.job, 'complete'),
},
{
label: 'Unknown',
value: allocs.unknownAllocs,
className: 'unknown',
legendLink: this.generateLegendLink(this.job, 'unknown'),
help: 'Allocation is unknown since its node is disconnected.',
},
{
label: 'Failed',
value: allocs.failedAllocs,

View File

@@ -23,6 +23,7 @@ export default class JobClientStatusBar extends DistributionBar {
failed,
lost,
notScheduled,
unknown,
} = this.jobClientStatus.byStatus;
return [
@@ -71,6 +72,18 @@ export default class JobClientStatusBar extends DistributionBar {
},
},
},
{
label: 'Unknown',
value: unknown.length,
className: 'unknown',
legendLink: {
queryParams: {
status: JSON.stringify(['unknown']),
namespace: this.job.namespace.get('id'),
},
},
help: 'Some allocations for this job were degraded or lost connectivity.',
},
{
label: 'Degraded',
value: degraded.length,

View File

@@ -48,6 +48,7 @@ export default class ClientRow extends Component {
runningAllocs: 0,
startingAllocs: 0,
lostAllocs: 0,
unknownAllocs: 0,
};
switch (this.args.row.model.jobStatus) {
@@ -77,6 +78,9 @@ export default class ClientRow extends Component {
case 'starting':
statusSummary.startingAllocs++;
break;
case 'unknown':
statusSummary.unknownAllocs++;
break;
}
}
}

View File

@@ -211,6 +211,7 @@ export default class ClientController extends Controller.extend(
{ key: 'complete', label: 'Complete' },
{ key: 'failed', label: 'Failed' },
{ key: 'lost', label: 'Lost' },
{ key: 'unknown', label: 'Unknown' },
];
}

View File

@@ -103,6 +103,7 @@ export default class IndexController extends Controller.extend(
{ key: 'down', label: 'Down' },
{ key: 'ineligible', label: 'Ineligible' },
{ key: 'draining', label: 'Draining' },
{ key: 'disconnected', label: 'Disconnected' },
];
}

View File

@@ -116,6 +116,7 @@ export default class AllocationsController extends Controller.extend(
{ key: 'complete', label: 'Complete' },
{ key: 'failed', label: 'Failed' },
{ key: 'lost', label: 'Lost' },
{ key: 'unknown', label: 'Unknown' },
];
}

View File

@@ -141,6 +141,7 @@ export default class ClientsController extends Controller.extend(
{ key: 'degraded', label: 'Degraded' },
{ key: 'failed', label: 'Failed' },
{ key: 'lost', label: 'Lost' },
{ key: 'unknown', label: 'Unknown' },
];
}

View File

@@ -139,6 +139,7 @@ export default class TaskGroupController extends Controller.extend(
{ key: 'complete', label: 'Complete' },
{ key: 'failed', label: 'Failed' },
{ key: 'lost', label: 'Lost' },
{ key: 'unknown', label: 'Unknown' },
];
}

View File

@@ -12,8 +12,9 @@ const STATUS_ORDER = {
pending: 1,
running: 2,
complete: 3,
failed: 4,
lost: 5,
unknown: 4,
failed: 5,
lost: 6,
};
@classic
@@ -83,6 +84,7 @@ export default class Allocation extends Model {
complete: 'is-complete',
failed: 'is-error',
lost: 'is-light',
unknown: 'is-unknown',
};
return classMap[this.clientStatus] || 'is-dark';

View File

@@ -17,6 +17,7 @@ export default class JobSummary extends Model {
@sumAggregation('taskGroupSummaries', 'runningAllocs') runningAllocs;
@sumAggregation('taskGroupSummaries', 'completeAllocs') completeAllocs;
@sumAggregation('taskGroupSummaries', 'failedAllocs') failedAllocs;
@sumAggregation('taskGroupSummaries', 'unknownAllocs') unknownAllocs;
@sumAggregation('taskGroupSummaries', 'lostAllocs') lostAllocs;
@collect(
@@ -25,7 +26,8 @@ export default class JobSummary extends Model {
'runningAllocs',
'completeAllocs',
'failedAllocs',
'lostAllocs'
'lostAllocs',
'unknownAllocs'
)
allocsList;

View File

@@ -131,6 +131,7 @@ export default class Job extends Model {
@alias('summary.completeAllocs') completeAllocs;
@alias('summary.failedAllocs') failedAllocs;
@alias('summary.lostAllocs') lostAllocs;
@alias('summary.unknownAllocs') unknownAllocs;
@alias('summary.totalAllocs') totalAllocs;
@alias('summary.pendingChildren') pendingChildren;
@alias('summary.runningChildren') runningChildren;

View File

@@ -13,6 +13,7 @@ export default class TaskGroupSummary extends Fragment {
@attr('number') completeAllocs;
@attr('number') failedAllocs;
@attr('number') lostAllocs;
@attr('number') unknownAllocs;
@collect(
'queuedAllocs',
@@ -20,7 +21,8 @@ export default class TaskGroupSummary extends Fragment {
'runningAllocs',
'completeAllocs',
'failedAllocs',
'lostAllocs'
'lostAllocs',
'unknownAllocs'
)
allocsList;

View File

@@ -49,6 +49,10 @@ $canceled: $dark;
.degraded {
fill: $degraded;
}
.unknown {
fill: $unknown;
}
}
.color-swatch {
@@ -114,6 +118,10 @@ $canceled: $dark;
background: $lost;
}
&.unknown {
background: $unknown;
}
&.not-scheduled {
background: $not-scheduled;
}

View File

@@ -25,7 +25,8 @@
opacity: 0;
}
$color-sequence: $orange, $yellow, $green, $turquoise, $blue, $purple, $red;
$color-sequence: $orange, $yellow, $green, $turquoise, $blue, $purple,
$red;
@for $i from 1 through length($color-sequence) {
.slice-#{$i - 1} {
@@ -113,6 +114,12 @@
color: darken($grey-blue, 20%);
}
}
// Prevent Orphaned last-elements in the list
// from being visually centered
&:nth-child(2n + 1):last-child {
margin-right: calc(35% + 0.75em);
}
}
}
}

View File

@@ -5,6 +5,10 @@
color: $nomad-green-dark;
}
&.node-disconnected {
color: $yellow;
}
&.node-down {
color: $danger;
}

View File

@@ -39,6 +39,11 @@
color: $orange-invert;
}
&.is-unknown {
background: $unknown;
color: $primary-invert;
}
&.is-hollow {
font-weight: $weight-semibold;
color: darken($grey-blue, 20%);

View File

@@ -5,12 +5,14 @@ $purple: $terraform-purple;
$red: #c84034;
$grey-blue: #bbc4d1;
$blue-light: #c0d5ff;
$yellow: #fac402;
$primary: $nomad-green;
$warning: $orange;
$warning-invert: $white;
$danger: $red;
$info: $blue;
$unknown: $yellow;
$dark: #234;
$dark-2: darken($dark, 5%);
$dark-3: darken($dark, 10%);
@@ -25,8 +27,8 @@ $size-7: 0.85rem;
$title-weight: $weight-semibold;
$family-sans-serif: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu,
Cantarell, 'Helvetica Neue', sans-serif;
$family-sans-serif: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
$text: $black;

View File

@@ -9,6 +9,7 @@ const STATUS = [
'degraded',
'failed',
'lost',
'unknown',
];
// An Ember.Computed property that computes the aggregated status of a job in a
@@ -137,5 +138,9 @@ function jobStatus(allocs, expected) {
return 'running';
}
if (summary['unknown'] > 0) {
return 'unknown';
}
return 'starting';
}

View File

@@ -9,7 +9,7 @@ export default Factory.extend({
namespace: null,
withSummary: trait({
Summary: function() {
Summary: function () {
return this.groupNames.reduce((summary, group) => {
summary[group] = {
Queued: faker.random.number(10),
@@ -18,6 +18,7 @@ export default Factory.extend({
Running: faker.random.number(10),
Starting: faker.random.number(10),
Lost: faker.random.number(10),
Unknown: faker.random.number(10),
};
return summary;
}, {});

View File

@@ -1140,12 +1140,21 @@ module('Acceptance | client detail', function (hooks) {
testFacet('Status', {
facet: ClientDetail.facets.status,
paramName: 'status',
expectedOptions: ['Pending', 'Running', 'Complete', 'Failed', 'Lost'],
expectedOptions: [
'Pending',
'Running',
'Complete',
'Failed',
'Lost',
'Unknown',
],
async beforeEach() {
server.createList('job', 5, { createAllocations: false });
['pending', 'running', 'complete', 'failed', 'lost'].forEach((s) => {
server.createList('allocation', 5, { clientStatus: s });
});
['pending', 'running', 'complete', 'failed', 'lost', 'unknown'].forEach(
(s) => {
server.createList('allocation', 5, { clientStatus: s });
}
);
await ClientDetail.visit({ id: node.id });
},

View File

@@ -276,6 +276,7 @@ module('Acceptance | clients list', function (hooks) {
'Down',
'Ineligible',
'Draining',
'Disconnected',
],
async beforeEach() {
server.create('agent');

View File

@@ -152,11 +152,20 @@ module('Acceptance | job allocations', function (hooks) {
testFacet('Status', {
facet: Allocations.facets.status,
paramName: 'status',
expectedOptions: ['Pending', 'Running', 'Complete', 'Failed', 'Lost'],
expectedOptions: [
'Pending',
'Running',
'Complete',
'Failed',
'Lost',
'Unknown',
],
async beforeEach() {
['pending', 'running', 'complete', 'failed', 'lost'].forEach((s) => {
server.createList('allocation', 5, { clientStatus: s });
});
['pending', 'running', 'complete', 'failed', 'lost', 'unknown'].forEach(
(s) => {
server.createList('allocation', 5, { clientStatus: s });
}
);
await Allocations.visit({ id: job.id });
},
filter: (alloc, selection) =>

View File

@@ -200,6 +200,7 @@ module('Acceptance | job clients', function (hooks) {
'Degraded',
'Failed',
'Lost',
'Unknown',
],
async beforeEach() {
await Clients.visit({ id: job.id });

View File

@@ -669,11 +669,20 @@ module('Acceptance | task group detail', function (hooks) {
testFacet('Status', {
facet: TaskGroup.facets.status,
paramName: 'status',
expectedOptions: ['Pending', 'Running', 'Complete', 'Failed', 'Lost'],
expectedOptions: [
'Pending',
'Running',
'Complete',
'Failed',
'Lost',
'Unknown',
],
async beforeEach() {
['pending', 'running', 'complete', 'failed', 'lost'].forEach((s) => {
server.createList('allocation', 5, { clientStatus: s });
});
['pending', 'running', 'complete', 'failed', 'lost', 'unknown'].forEach(
(s) => {
server.createList('allocation', 5, { clientStatus: s });
}
);
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
},
filter: (alloc, selection) =>

View File

@@ -29,6 +29,7 @@ module('Integration | Component | job-client-status-bar', function (hooks) {
failed: [],
lost: [],
notScheduled: [],
unknown: [],
},
},
isNarrow: true,

View File

@@ -19,6 +19,7 @@ module('Unit | Model | job', function (hooks) {
completeAllocs: 4,
failedAllocs: 5,
lostAllocs: 6,
unknownAllocs: 7,
},
{
name: 'two',
@@ -28,6 +29,7 @@ module('Unit | Model | job', function (hooks) {
completeAllocs: 8,
failedAllocs: 10,
lostAllocs: 12,
unknownAllocs: 14,
},
{
name: 'three',
@@ -37,6 +39,7 @@ module('Unit | Model | job', function (hooks) {
completeAllocs: 12,
failedAllocs: 15,
lostAllocs: 18,
unknownAllocs: 21,
},
],
});

View File

@@ -74,6 +74,7 @@ module('Unit | Util | JobClientStatus', function () {
notScheduled: [],
queued: [],
starting: [],
unknown: [],
},
totalNodes: 1,
};
@@ -110,6 +111,7 @@ module('Unit | Util | JobClientStatus', function () {
notScheduled: [],
queued: [],
starting: [],
unknown: [],
},
totalNodes: 1,
};
@@ -146,6 +148,7 @@ module('Unit | Util | JobClientStatus', function () {
notScheduled: [],
queued: [],
starting: [],
unknown: [],
},
totalNodes: 1,
};
@@ -182,6 +185,7 @@ module('Unit | Util | JobClientStatus', function () {
notScheduled: [],
queued: [],
starting: [],
unknown: [],
},
totalNodes: 1,
};
@@ -218,6 +222,7 @@ module('Unit | Util | JobClientStatus', function () {
notScheduled: [],
queued: [],
starting: [],
unknown: [],
},
totalNodes: 1,
};
@@ -250,6 +255,7 @@ module('Unit | Util | JobClientStatus', function () {
notScheduled: ['node-1'],
queued: [],
starting: [],
unknown: [],
},
totalNodes: 1,
};
@@ -286,6 +292,7 @@ module('Unit | Util | JobClientStatus', function () {
notScheduled: [],
queued: ['node-1'],
starting: [],
unknown: [],
},
totalNodes: 1,
};
@@ -323,6 +330,7 @@ module('Unit | Util | JobClientStatus', function () {
notScheduled: [],
queued: [],
starting: [],
unknown: [],
},
totalNodes: 1,
};