github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/controllers/jobs/job/clients.js (about)

     1  /* eslint-disable ember/no-incorrect-calls-with-inline-anonymous-functions */
     2  import Controller from '@ember/controller';
     3  import { action, computed } from '@ember/object';
     4  import { scheduleOnce } from '@ember/runloop';
     5  import intersection from 'lodash.intersection';
     6  import { alias } from '@ember/object/computed';
     7  import SortableFactory from 'nomad-ui/mixins/sortable-factory';
     8  import Searchable from 'nomad-ui/mixins/searchable';
     9  import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
    10  import jobClientStatus from 'nomad-ui/utils/properties/job-client-status';
    11  import {
    12    serialize,
    13    deserializedQueryParam as selection,
    14  } from 'nomad-ui/utils/qp-serialize';
    15  import classic from 'ember-classic-decorator';
    16  import { inject as service } from '@ember/service';
    17  
    18  @classic
    19  export default class ClientsController extends Controller.extend(
    20    SortableFactory(['id', 'name', 'jobStatus']),
    21    Searchable,
    22    WithNamespaceResetting
    23  ) {
    24    @service store;
    25  
    26    queryParams = [
    27      {
    28        currentPage: 'page',
    29      },
    30      {
    31        searchTerm: 'search',
    32      },
    33      {
    34        qpStatus: 'status',
    35      },
    36      {
    37        qpDatacenter: 'dc',
    38      },
    39      {
    40        qpClientClass: 'clientclass',
    41      },
    42      {
    43        sortProperty: 'sort',
    44      },
    45      {
    46        sortDescending: 'desc',
    47      },
    48    ];
    49  
    50    qpStatus = '';
    51    qpDatacenter = '';
    52    qpClientClass = '';
    53  
    54    currentPage = 1;
    55    pageSize = 25;
    56  
    57    sortProperty = 'jobStatus';
    58    sortDescending = false;
    59  
    60    @selection('qpStatus') selectionStatus;
    61    @selection('qpDatacenter') selectionDatacenter;
    62    @selection('qpClientClass') selectionClientClass;
    63  
    64    @alias('model') job;
    65    @jobClientStatus('allNodes', 'job') jobClientStatus;
    66  
    67    @alias('filteredNodes') listToSort;
    68    @alias('listSorted') listToSearch;
    69    @alias('listSearched') sortedClients;
    70  
    71    @computed('store')
    72    get allNodes() {
    73      return this.store.peekAll('node');
    74    }
    75  
    76    @computed('allNodes', 'jobClientStatus.byNode')
    77    get nodes() {
    78      return this.allNodes.filter((node) => this.jobClientStatus.byNode[node.id]);
    79    }
    80  
    81    @computed
    82    get searchProps() {
    83      return ['node.id', 'node.name'];
    84    }
    85  
    86    @computed(
    87      'nodes',
    88      'job.allocations',
    89      'jobClientStatus.byNode',
    90      'selectionStatus',
    91      'selectionDatacenter',
    92      'selectionClientClass'
    93    )
    94    get filteredNodes() {
    95      const {
    96        selectionStatus: statuses,
    97        selectionDatacenter: datacenters,
    98        selectionClientClass: clientClasses,
    99      } = this;
   100  
   101      return this.nodes
   102        .filter((node) => {
   103          if (
   104            statuses.length &&
   105            !statuses.includes(this.jobClientStatus.byNode[node.id])
   106          ) {
   107            return false;
   108          }
   109          if (datacenters.length && !datacenters.includes(node.datacenter)) {
   110            return false;
   111          }
   112          if (clientClasses.length && !clientClasses.includes(node.nodeClass)) {
   113            return false;
   114          }
   115  
   116          return true;
   117        })
   118        .map((node) => {
   119          const allocations = this.job.allocations.filter(
   120            (alloc) => alloc.get('node.id') == node.id
   121          );
   122  
   123          return {
   124            node,
   125            jobStatus: this.jobClientStatus.byNode[node.id],
   126            allocations,
   127            createTime: eldestCreateTime(allocations),
   128            modifyTime: mostRecentModifyTime(allocations),
   129          };
   130        });
   131    }
   132  
   133    @computed
   134    get optionsJobStatus() {
   135      return [
   136        { key: 'queued', label: 'Queued' },
   137        { key: 'notScheduled', label: 'Not Scheduled' },
   138        { key: 'starting', label: 'Starting' },
   139        { key: 'running', label: 'Running' },
   140        { key: 'complete', label: 'Complete' },
   141        { key: 'degraded', label: 'Degraded' },
   142        { key: 'failed', label: 'Failed' },
   143        { key: 'lost', label: 'Lost' },
   144        { key: 'unknown', label: 'Unknown' },
   145      ];
   146    }
   147  
   148    @computed('selectionDatacenter', 'nodes')
   149    get optionsDatacenter() {
   150      const datacenters = Array.from(
   151        new Set(this.nodes.mapBy('datacenter'))
   152      ).compact();
   153  
   154      // Update query param when the list of datacenters changes.
   155      scheduleOnce('actions', () => {
   156        // eslint-disable-next-line ember/no-side-effects
   157        this.set(
   158          'qpDatacenter',
   159          serialize(intersection(datacenters, this.selectionDatacenter))
   160        );
   161      });
   162  
   163      return datacenters.sort().map((dc) => ({ key: dc, label: dc }));
   164    }
   165  
   166    @computed('selectionClientClass', 'nodes')
   167    get optionsClientClass() {
   168      const clientClasses = Array.from(
   169        new Set(this.nodes.mapBy('nodeClass'))
   170      ).compact();
   171  
   172      // Update query param when the list of datacenters changes.
   173      scheduleOnce('actions', () => {
   174        // eslint-disable-next-line ember/no-side-effects
   175        this.set(
   176          'qpClientClass',
   177          serialize(intersection(clientClasses, this.selectionClientClass))
   178        );
   179      });
   180  
   181      return clientClasses
   182        .sort()
   183        .map((clientClass) => ({ key: clientClass, label: clientClass }));
   184    }
   185  
   186    @action
   187    gotoClient(client) {
   188      this.transitionToRoute('clients.client', client);
   189    }
   190  
   191    setFacetQueryParam(queryParam, selection) {
   192      this.set(queryParam, serialize(selection));
   193    }
   194  }
   195  
   196  function eldestCreateTime(allocations) {
   197    let eldest = null;
   198    for (const alloc of allocations) {
   199      if (!eldest || alloc.createTime < eldest) {
   200        eldest = alloc.createTime;
   201      }
   202    }
   203    return eldest;
   204  }
   205  
   206  function mostRecentModifyTime(allocations) {
   207    let mostRecent = null;
   208    for (const alloc of allocations) {
   209      if (!mostRecent || alloc.modifyTime > mostRecent) {
   210        mostRecent = alloc.modifyTime;
   211      }
   212    }
   213    return mostRecent;
   214  }