From 48910d8334933a17cf48e3e45a7dc5bfb3d1f3c1 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Thu, 13 Sep 2018 16:32:29 -0700 Subject: [PATCH] New primary-metric component It encapsulates all the tracker, polling, and markup for this style of metric. --- ui/app/components/primary-metric.js | 103 ++++++++++++++++++ .../templates/components/primary-metric.hbs | 26 +++++ .../utils/classes/abstract-stats-tracker.js | 4 +- 3 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 ui/app/components/primary-metric.js create mode 100644 ui/app/templates/components/primary-metric.hbs diff --git a/ui/app/components/primary-metric.js b/ui/app/components/primary-metric.js new file mode 100644 index 000000000..8423af248 --- /dev/null +++ b/ui/app/components/primary-metric.js @@ -0,0 +1,103 @@ +import Ember from 'ember'; +import Component from '@ember/component'; +import { inject as service } from '@ember/service'; +import { computed } from '@ember/object'; +import NodeStatsTracker from 'nomad-ui/utils/classes/node-stats-tracker'; +import AllocationStatsTracker from 'nomad-ui/utils/classes/allocation-stats-tracker'; +import { task, timeout } from 'ember-concurrency'; + +export default Component.extend({ + token: service(), + + // One of Node, Allocation, or TaskState + resource: null, + + // cpu or memory + metric: null, + + // An instance of a StatsTracker. An alternative interface to resource + tracker: computed('trackedResource', 'type', function() { + const resource = this.get('trackedResource'); + + if (!resource) return; + + const Constructor = this.get('type') === 'node' ? NodeStatsTracker : AllocationStatsTracker; + const resourceProp = this.get('type') === 'node' ? 'node' : 'allocation'; + return Constructor.create({ + fetch: url => this.get('token').authorizedRequest(url), + [resourceProp]: resource, + }); + }), + + type: computed('resource', function() { + const resource = this.get('resource'); + return resource && resource.constructor.modelName; + }), + + trackedResource: computed('resource', 'type', function() { + // TaskStates use the allocation stats tracker + return this.get('type') === 'task-state' + ? this.get('resource.allocation') + : this.get('resource'); + }), + + metricLabel: computed('metric', function() { + const metric = this.get('metric'); + const mappings = { + cpu: 'CPU', + memory: 'Memory', + }; + return mappings[metric] || metric; + }), + + data: computed('resource', 'metric', 'type', function() { + if (!this.get('tracker')) return []; + + const metric = this.get('metric'); + if (this.get('type') === 'task-state') { + // handle getting the right task out of the tracker + const task = this.get('tracker.tasks').findBy('task', this.get('resource.name')); + return task && task[metric]; + } + + return this.get(`tracker.${metric}`); + }), + + reservedAmount: computed('resource', 'metric', 'type', function() { + const metricProperty = this.get('metric') === 'cpu' ? 'reservedCPU' : 'reservedMemory'; + + if (this.get('type') === 'task-state') { + const task = this.get('tracker.tasks').findBy('task', this.get('resource.name')); + return task[metricProperty]; + } + + return this.get(`tracker.${metricProperty}`); + }), + + chartClass: computed('metric', function() { + const metric = this.get('metric'); + const mappings = { + cpu: 'is-info', + memory: 'is-danger', + }; + + return mappings[metric] || 'is-primary'; + }), + + poller: task(function*() { + do { + yield this.get('tracker').poll(); + yield timeout(2000); + } while (!Ember.testing); + }), + + didReceiveAttrs() { + if (this.get('tracker')) { + this.get('poller').perform(); + } + }, + + willDestroy() { + this.get('poller').cancelAll(); + }, +}); diff --git a/ui/app/templates/components/primary-metric.hbs b/ui/app/templates/components/primary-metric.hbs new file mode 100644 index 000000000..d8d4ab9ac --- /dev/null +++ b/ui/app/templates/components/primary-metric.hbs @@ -0,0 +1,26 @@ +{{metricLabel}} +
+ {{stats-time-series data=data chartClass=chartClass}} +
+
+
+
+ + {{data.lastObject.percent}} + +
+
+
+ {{format-percentage data.lastObject.percent total=1}} +
+
+{{#if (eq metric "cpu")}} + {{data.lastObject.used}} Mhz / {{reservedAmount}} Mhz reserved +{{else if (eq metric "memory")}} + {{format-bytes data.lastObject.used}} MiB / {{reservedAmount}} MiB reserved +{{else}} + {{data.lastObject.used}} / {{reservedAmount}} reserved +{{/if}} diff --git a/ui/app/utils/classes/abstract-stats-tracker.js b/ui/app/utils/classes/abstract-stats-tracker.js index 488dec465..4569b29b5 100644 --- a/ui/app/utils/classes/abstract-stats-tracker.js +++ b/ui/app/utils/classes/abstract-stats-tracker.js @@ -19,9 +19,7 @@ export default Mixin.create({ assert('Url must be defined', url); return this.get('fetch')(url) - .then(res => { - return res.json(); - }) + .then(res => res.json()) .then(frame => this.append(frame)); }, });