From 40e18c0e456b3c86c0c69e67d774263d175d1aaa Mon Sep 17 00:00:00 2001 From: Michael Klein Date: Tue, 11 Oct 2022 11:17:19 +0200 Subject: [PATCH] Add peer as a belongs-to to service Working with a peer model as a relationship is much easier than to workaround a non-relationship in imported services. This is currently only relevant for imported-services where we know the peer in advance. --- ui/packages/consul-ui/app/models/service.js | 47 ++++++++++++++++++- .../app/services/repository/service.js | 21 +++++++-- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/ui/packages/consul-ui/app/models/service.js b/ui/packages/consul-ui/app/models/service.js index 70a753f44f..7b50315d77 100644 --- a/ui/packages/consul-ui/app/models/service.js +++ b/ui/packages/consul-ui/app/models/service.js @@ -1,4 +1,4 @@ -import Model, { attr } from '@ember-data/model'; +import Model, { attr, belongsTo } from '@ember-data/model'; import { computed } from '@ember/object'; import { tracked } from '@glimmer/tracking'; import { fragment } from 'ember-data-model-fragments/attributes'; @@ -58,6 +58,18 @@ export default class Service extends Model { @attr() meta; // {} + @belongsTo({ async: false }) peer; + + @computed('peer', 'InstanceCount') + get isZeroCountButPeered() { + return this.peer && this.InstanceCount === 0; + } + + @computed('peer.State') + get peerIsFailing() { + return this.peer && this.peer.State === 'FAILING'; + } + @computed('ChecksPassing', 'ChecksWarning', 'ChecksCritical') get ChecksTotal() { return this.ChecksPassing + this.ChecksWarning + this.ChecksCritical; @@ -79,9 +91,19 @@ export default class Service extends Model { return this.MeshEnabled || (this.Kind || '').length > 0; } - @computed('MeshChecksPassing', 'MeshChecksWarning', 'MeshChecksCritical') + @computed( + 'MeshChecksPassing', + 'MeshChecksWarning', + 'MeshChecksCritical', + 'isZeroCountButPeered', + 'peerIsFailing' + ) get MeshStatus() { switch (true) { + case this.isZeroCountButPeered: + return 'unknown'; + case this.peerIsFailing: + return 'unknown'; case this.MeshChecksCritical !== 0: return 'critical'; case this.MeshChecksWarning !== 0: @@ -93,6 +115,27 @@ export default class Service extends Model { } } + @computed('isZeroCountButPeered', 'peerIsFailing', 'MeshStatus') + get healthTooltipText() { + const { MeshStatus, isZeroCountButPeered, peerIsFailing } = this; + if (isZeroCountButPeered) { + return 'This service currently has 0 instances. Check with the operator of its peer to make sure this is expected behavior.'; + } + if (peerIsFailing) { + return 'This peer is out of sync, so the current health statuses of its services are unknown.'; + } + if (MeshStatus === 'critical') { + return 'At least one health check on one instance is failing.'; + } + if (MeshStatus === 'warning') { + return 'At least one health check on one instance has a warning.'; + } + if (MeshStatus == 'passing') { + return 'All health checks are passing.'; + } + return 'There are no health checks'; + } + @computed('ChecksPassing', 'Proxy.ChecksPassing') get MeshChecksPassing() { let proxyCount = 0; diff --git a/ui/packages/consul-ui/app/services/repository/service.js b/ui/packages/consul-ui/app/services/repository/service.js index 269e4a20b8..7219983329 100644 --- a/ui/packages/consul-ui/app/services/repository/service.js +++ b/ui/packages/consul-ui/app/services/repository/service.js @@ -1,8 +1,11 @@ import RepositoryService from 'consul-ui/services/repository'; import dataSource from 'consul-ui/decorators/data-source'; +import { inject as service } from '@ember/service'; const modelName = 'service'; export default class ServiceService extends RepositoryService { + @service store; + getModelName() { return modelName; } @@ -12,9 +15,21 @@ export default class ServiceService extends RepositoryService { return super.findAll(...arguments); } - @dataSource('/:partition/:ns/:dc/services/:peer') - async findAllImportedServices() { - return super.findAll(...arguments); + @dataSource('/:partition/:ns/:dc/services/:peer/:peerId') + async findAllImportedServices(params, configuration) { + // remember peer.id so that we can add it to to the service later on to setup relationship + const { peerId } = params; + + // don't send peerId with query + delete params.peerId; + + // assign the peer as a belongs-to. we don't have access to any information + // we could use to do this in the serializer so we need to do it manually here + return super.findAll(params, configuration).then((services) => { + const peer = this.store.peekRecord('peer', peerId); + services.forEach((service) => (service.peer = peer)); + return services; + }); } @dataSource('/:partition/:ns/:dc/gateways/for-service/:gateway')