diff --git a/ui/app/components/task-log.js b/ui/app/components/task-log.js index fcc911a1c..2cc8617e4 100644 --- a/ui/app/components/task-log.js +++ b/ui/app/components/task-log.js @@ -16,8 +16,15 @@ export default Component.extend(WindowResizable, { allocation: null, task: null, + // When true, request logs from the server agent useServer: false, + // When true, logs cannot be fetched from either the client or the server + noConnection: false, + + clientTimeout: 1000, + serverTimeout: 5000, + didReceiveAttrs() { if (this.get('allocation') && this.get('task')) { this.send('toggleStream'); @@ -59,12 +66,17 @@ export default Component.extend(WindowResizable, { logger: logger('logUrl', 'logParams', function logFetch() { // If the log request can't settle in one second, the client // must be unavailable and the server should be used instead + const timing = this.get('useServer') ? this.get('serverTimeout') : this.get('clientTimeout'); return url => - RSVP.race([this.get('token').authorizedRequest(url), timeout(1000)]).then( + RSVP.race([this.get('token').authorizedRequest(url), timeout(timing)]).then( response => response, error => { - this.send('failoverToServer'); - this.get('stream').perform(); + if (this.get('useServer')) { + this.set('noConnection', true); + } else { + this.send('failoverToServer'); + this.get('stream').perform(); + } throw error; } ); diff --git a/ui/app/templates/components/task-log.hbs b/ui/app/templates/components/task-log.hbs index ce0d0ae9c..6c3991a35 100644 --- a/ui/app/templates/components/task-log.hbs +++ b/ui/app/templates/components/task-log.hbs @@ -1,3 +1,9 @@ +{{#if noConnection}} +
+

Cannot fetch logs

+

The logs for this task are inaccessible. Check the condition of the node the allocation is on.

+
+{{/if}}
diff --git a/ui/tests/integration/task-log-test.js b/ui/tests/integration/task-log-test.js index cf60e5999..f6a7416fd 100644 --- a/ui/tests/integration/task-log-test.js +++ b/ui/tests/integration/task-log-test.js @@ -7,6 +7,7 @@ import Pretender from 'pretender'; import { logEncode } from '../../mirage/data/logs'; const HOST = '1.1.1.1:1111'; +const allowedConnectionTime = 100; const commonProps = { interval: 50, allocation: { @@ -16,6 +17,8 @@ const commonProps = { }, }, task: 'task-name', + clientTimeout: allowedConnectionTime, + serverTimeout: allowedConnectionTime, }; const logHead = ['HEAD']; @@ -179,13 +182,23 @@ test('Clicking stderr switches the log to standard error', function(assert) { }); test('When the client is inaccessible, task-log falls back to requesting logs through the server', function(assert) { - run.later(run, run.cancelTimers, 2000); + run.later(run, run.cancelTimers, allowedConnectionTime * 2); // override client response to timeout - this.server.get(`http://${HOST}/v1/client/fs/logs/:allocation_id`, () => [400, {}, ''], 2000); + this.server.get( + `http://${HOST}/v1/client/fs/logs/:allocation_id`, + () => [400, {}, ''], + allowedConnectionTime * 2 + ); this.setProperties(commonProps); - this.render(hbs`{{task-log allocation=allocation task=task}}`); + this.render( + hbs`{{task-log + allocation=allocation + task=task + clientTimeout=clientTimeout + serverTimeout=serverTimeout}}` + ); const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); assert.ok( @@ -201,3 +214,42 @@ test('When the client is inaccessible, task-log falls back to requesting logs th ); }); }); + +test('When both the client and the server are inaccessible, an error message is shown', function(assert) { + run.later(run, run.cancelTimers, allowedConnectionTime * 5); + + // override client and server responses to timeout + this.server.get( + `http://${HOST}/v1/client/fs/logs/:allocation_id`, + () => [400, {}, ''], + allowedConnectionTime * 2 + ); + this.server.get( + '/v1/client/fs/logs/:allocation_id', + () => [400, {}, ''], + allowedConnectionTime * 2 + ); + + this.setProperties(commonProps); + this.render( + hbs`{{task-log + allocation=allocation + task=task + clientTimeout=clientTimeout + serverTimeout=serverTimeout}}` + ); + + return wait().then(() => { + const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); + assert.ok( + this.server.handledRequests.filter(req => clientUrlRegex.test(req.url)).length, + 'Log request was initially made directly to the client' + ); + const serverUrl = `/v1/client/fs/logs/${commonProps.allocation.id}`; + assert.ok( + this.server.handledRequests.filter(req => req.url.startsWith(serverUrl)).length, + 'Log request was later made to the server' + ); + assert.ok(find('[data-test-connection-error]'), 'An error message is shown'); + }); +});