Skip to content

Commit

Permalink
Merge pull request #14404 from hashicorp/f-ui/dupe-serv
Browse files Browse the repository at this point in the history
[ui] handle visualizing health status checks for duplicate services
  • Loading branch information
philrenaud committed Aug 31, 2022
2 parents b9369e1 + 0ce11d5 commit 50aef45
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 31 deletions.
7 changes: 6 additions & 1 deletion ui/app/controllers/allocations/allocation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,13 @@ export default class IndexController extends Controller.extend(Sortable) {

let result = new Map();
Object.values(this.model.healthChecks)?.forEach((service) => {
const isTask = !!service.Task;
const groupName = service.Group.split('.')[1].split('[')[0];
const currentServiceStatus = service.Status;
const currentServiceName = service.Service;

const currentServiceName = isTask
? service.Task.concat(`-${service.Service}`)
: groupName.concat(`-${service.Service}`);
const serviceStatuses = result.get(currentServiceName);
if (serviceStatuses) {
if (serviceStatuses[currentServiceStatus]) {
Expand Down
6 changes: 6 additions & 0 deletions ui/app/models/service-fragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ export default class Service extends Fragment {
@attr('string') onUpdate;
@attr('string') provider;
@fragment('consul-connect') connect;
@attr() groupName;
@attr() taskName;

get refID() {
return `${this.groupName || this.taskName}-${this.name}`;
}
}
8 changes: 4 additions & 4 deletions ui/app/routes/allocations/allocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ export default class AllocationRoute extends Route.extend(WithWatchers) {

// Conditionally Long Poll /checks endpoint if alloc has nomad services
const doesAllocHaveServices =
!!model.taskGroup.services.filterBy('provider', 'nomad').length ||
!!model.taskGroup?.services?.filterBy('provider', 'nomad').length ||
!!model.states
.mapBy('task')
.map((t) => t && t.get('services'))[0]
.filterBy('provider', 'nomad').length;
?.mapBy('task')
?.map((t) => t && t.get('services'))[0]
?.filterBy('provider', 'nomad').length;

if (doesAllocHaveServices) {
controller.set(
Expand Down
6 changes: 6 additions & 0 deletions ui/app/serializers/task-group.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ export default class TaskGroup extends ApplicationSerializer {
mapToArray = ['Volumes'];

normalize(typeHash, hash) {
if (hash.Services) {
hash.Services.forEach((service) => {
service.GroupName = hash.Name;
});
}

// Provide EphemeralDisk to each task
hash.Tasks.forEach((task) => {
task.EphemeralDisk = copy(hash.EphemeralDisk);
Expand Down
6 changes: 5 additions & 1 deletion ui/app/templates/allocations/allocation/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,11 @@
<td data-test-service-health>
{{#if (eq row.model.provider "nomad")}}
<div class="inline-chart">
<ServiceStatusBar @isNarrow={{true}} @services={{this.serviceHealthStatuses}} @name={{row.model.name}} />
{{#if (is-empty row.model.taskName)}}
<ServiceStatusBar @isNarrow={{true}} @services={{this.serviceHealthStatuses}} @name={{concat row.model.groupName "-" row.model.name}} />
{{else}}
<ServiceStatusBar @isNarrow={{true}} @services={{this.serviceHealthStatuses}} @name={{concat row.model.taskName "-" row.model.name}} />
{{/if}}
</div>
{{/if}}
</td>
Expand Down
32 changes: 16 additions & 16 deletions ui/tests/integration/components/service-status-bar-test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { A } from '@ember/array';
import EmberObject from '@ember/object';
import { findAll, render } from '@ember/test-helpers';
import { setupRenderingTest } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
Expand All @@ -14,28 +12,30 @@ module('Integration | Component | Service Status Bar', function (hooks) {
const component = this;
await componentA11yAudit(component, assert);

const healthyService = EmberObject.create({
id: '1',
status: 'success',
});
const healthyService = {
success: 1,
};

const failingService = EmberObject.create({
id: '2',
status: 'failing',
});
const failingService = {
failure: 1,
};

const pendingService = EmberObject.create({
id: '3',
status: 'pending',
});
const pendingService = {
pending: 1,
};

const services = new Map();
services.set('peter', healthyService);
services.set('peter', { ...services.get('peter'), ...failingService });
services.set('peter', { ...services.get('peter'), ...pendingService });

const services = A([healthyService, failingService, pendingService]);
this.set('services', services);

await render(hbs`
<div class="inline-chart">
<ServiceStatusBar
@services={{this.services}}
@services={{this.services}}
@name="peter"
/>
</div>
`);
Expand Down
72 changes: 63 additions & 9 deletions ui/tests/unit/controllers/allocations/allocation/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,89 @@ module('Unit | Controller | allocations/allocation/index', function (hooks) {
controller.set('model', Allocation);

const result = new Map();
result.set('fake-py', {
result.set('fakepy-fake-py', {
failure: 1,
success: 1,
});
result.set('task-fake-py', {
result.set('http.server-task-fake-py', {
failure: 1,
success: 1,
});
result.set('web', {
result.set('http.server-web', {
success: 1,
});

const fakePy = controller.serviceHealthStatuses.get('fake-py');
const taskFakePy = controller.serviceHealthStatuses.get('task-fake-py');
const web = controller.serviceHealthStatuses.get('web');
const fakePy = controller.serviceHealthStatuses.get('fakepy-fake-py');
const taskFakePy = controller.serviceHealthStatuses.get(
'http.server-task-fake-py'
);
const web = controller.serviceHealthStatuses.get('http.server-web');

assert.deepEqual(
fakePy,
result.get('fakepy-fake-py'),
'Service Health Check data is transformed and grouped by Service name'
);
assert.deepEqual(
taskFakePy,
result.get('http.server-task-fake-py'),
'Service Health Check data is transformed and grouped by Service name'
);
assert.deepEqual(
web,
result.get('http.server-web'),
'Service Health Check data is transformed and grouped by Service name'
);
});

test('it handles duplicate names', function (assert) {
let controller = this.owner.lookup(
'controller:allocations/allocation/index'
);

const dupeTaskLevelService =
Allocation.allocationTaskGroup.Tasks[0].Services[0];
dupeTaskLevelService.Name = 'fake-py';
dupeTaskLevelService.isTaskLevel = true;

const healthChecks = Allocation.healthChecks;
healthChecks['73ad9b936fb3f3cc4d7f62a1aab6de53'].Service = 'fake-py';
healthChecks['19421ef816ae0d3eeeb81697bce0e261'].Service = 'fake-py';

controller.set('model', Allocation);

const result = new Map();
result.set('fakepy-fake-py', {
failure: 1,
success: 1,
});
result.set('http.server-fake-py', {
failure: 1,
success: 1,
});
result.set('http.server-web', {
success: 1,
});

const fakePy = controller.serviceHealthStatuses.get('fakepy-fake-py');
const taskFakePy = controller.serviceHealthStatuses.get(
'http.server-fake-py'
);
const web = controller.serviceHealthStatuses.get('http.server-web');

assert.deepEqual(
fakePy,
result.get('fake-py'),
result.get('fakepy-fake-py'),
'Service Health Check data is transformed and grouped by Service name'
);
assert.deepEqual(
taskFakePy,
result.get('task-fake-py'),
result.get('http.server-fake-py'),
'Service Health Check data is transformed and grouped by Service name'
);
assert.deepEqual(
web,
result.get('web'),
result.get('http.server-web'),
'Service Health Check data is transformed and grouped by Service name'
);
});
Expand Down

0 comments on commit 50aef45

Please sign in to comment.