open-nomad/ui/app/controllers/jobs/job/clients.js

193 lines
5.2 KiB
JavaScript

/* eslint-disable ember/no-incorrect-calls-with-inline-anonymous-functions */
import Controller from '@ember/controller';
import { action, computed } from '@ember/object';
import { scheduleOnce } from '@ember/runloop';
import intersection from 'lodash.intersection';
import { alias } from '@ember/object/computed';
import SortableFactory from 'nomad-ui/mixins/sortable-factory';
import Searchable from 'nomad-ui/mixins/searchable';
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
import jobClientStatus from 'nomad-ui/utils/properties/job-client-status';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import classic from 'ember-classic-decorator';
@classic
export default class ClientsController extends Controller.extend(
SortableFactory(['id', 'name', 'jobStatus']),
Searchable,
WithNamespaceResetting
) {
queryParams = [
{
currentPage: 'page',
},
{
searchTerm: 'search',
},
{
qpStatus: 'status',
},
{
qpDatacenter: 'dc',
},
{
qpClientClass: 'clientclass',
},
{
sortProperty: 'sort',
},
{
sortDescending: 'desc',
},
];
qpStatus = '';
qpDatacenter = '';
qpClientClass = '';
currentPage = 1;
pageSize = 25;
sortProperty = 'jobStatus';
sortDescending = false;
@selection('qpStatus') selectionStatus;
@selection('qpDatacenter') selectionDatacenter;
@selection('qpClientClass') selectionClientClass;
@alias('model') job;
@jobClientStatus('allNodes', 'job') jobClientStatus;
@alias('filteredNodes') listToSort;
@alias('listSorted') listToSearch;
@alias('listSearched') sortedClients;
@computed('store')
get allNodes() {
return this.store.peekAll('node').length
? this.store.peekAll('node')
: this.store.findAll('node');
}
@computed('allNodes', 'jobClientStatus.byNode')
get nodes() {
return this.allNodes.filter(node => this.jobClientStatus.byNode[node.id]);
}
@computed
get searchProps() {
return ['node.id', 'node.name'];
}
@computed(
'nodes',
'job.allocations',
'jobClientStatus.byNode',
'selectionStatus',
'selectionDatacenter',
'selectionClientClass'
)
get filteredNodes() {
const {
selectionStatus: statuses,
selectionDatacenter: datacenters,
selectionClientClass: clientClasses,
} = this;
return this.nodes
.filter(node => {
if (statuses.length && !statuses.includes(this.jobClientStatus.byNode[node.id])) {
return false;
}
if (datacenters.length && !datacenters.includes(node.datacenter)) {
return false;
}
if (clientClasses.length && !clientClasses.includes(node.nodeClass)) {
return false;
}
return true;
})
.map(node => {
const allocations = this.job.allocations.filter(alloc => alloc.get('node.id') == node.id);
return {
node,
jobStatus: this.jobClientStatus.byNode[node.id],
allocations,
createTime: eldestCreateTime(allocations),
modifyTime: mostRecentModifyTime(allocations),
};
});
}
@computed
get optionsJobStatus() {
return [
{ key: 'queued', label: 'Queued' },
{ key: 'notScheduled', label: 'Not Scheduled' },
{ key: 'starting', label: 'Starting' },
{ key: 'running', label: 'Running' },
{ key: 'complete', label: 'Complete' },
{ key: 'degraded', label: 'Degraded' },
{ key: 'failed', label: 'Failed' },
{ key: 'lost', label: 'Lost' },
];
}
@computed('selectionDatacenter', 'nodes')
get optionsDatacenter() {
const datacenters = Array.from(new Set(this.nodes.mapBy('datacenter'))).compact();
// Update query param when the list of datacenters changes.
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpDatacenter', serialize(intersection(datacenters, this.selectionDatacenter)));
});
return datacenters.sort().map(dc => ({ key: dc, label: dc }));
}
@computed('selectionClientClass', 'nodes')
get optionsClientClass() {
const clientClasses = Array.from(new Set(this.nodes.mapBy('nodeClass'))).compact();
// Update query param when the list of datacenters changes.
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpClientClass', serialize(intersection(clientClasses, this.selectionClientClass)));
});
return clientClasses.sort().map(clientClass => ({ key: clientClass, label: clientClass }));
}
@action
gotoClient(client) {
this.transitionToRoute('clients.client', client);
}
setFacetQueryParam(queryParam, selection) {
this.set(queryParam, serialize(selection));
}
}
function eldestCreateTime(allocations) {
let eldest = null;
for (const alloc of allocations) {
if (!eldest || alloc.createTime < eldest) {
eldest = alloc.createTime;
}
}
return eldest;
}
function mostRecentModifyTime(allocations) {
let mostRecent = null;
for (const alloc of allocations) {
if (!mostRecent || alloc.modifyTime > mostRecent) {
mostRecent = alloc.modifyTime;
}
}
return mostRecent;
}