github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/controllers/exec.js (about) 1 import { inject as service } from '@ember/service'; 2 import Controller from '@ember/controller'; 3 import { action, computed } from '@ember/object'; 4 import { alias, mapBy, sort, uniq } from '@ember/object/computed'; 5 import escapeTaskName from 'nomad-ui/utils/escape-task-name'; 6 import ExecCommandEditorXtermAdapter from 'nomad-ui/utils/classes/exec-command-editor-xterm-adapter'; 7 import ExecSocketXtermAdapter from 'nomad-ui/utils/classes/exec-socket-xterm-adapter'; 8 import localStorageProperty from 'nomad-ui/utils/properties/local-storage'; 9 import classic from 'ember-classic-decorator'; 10 11 const ANSI_UI_GRAY_400 = '\x1b[38;2;142;150;163m'; 12 const ANSI_WHITE = '\x1b[0m'; 13 14 @classic 15 export default class ExecController extends Controller { 16 @service sockets; 17 @service system; 18 @service token; 19 20 queryParams = ['allocation', 'namespace']; 21 22 @localStorageProperty('nomadExecCommand', '/bin/bash') command; 23 socketOpen = false; 24 25 @computed('model.allocations.@each.clientStatus') 26 get pendingAndRunningAllocations() { 27 return this.model.allocations.filter( 28 (allocation) => 29 allocation.clientStatus === 'pending' || 30 allocation.clientStatus === 'running' 31 ); 32 } 33 34 @mapBy('pendingAndRunningAllocations', 'taskGroup') 35 pendingAndRunningTaskGroups; 36 @uniq('pendingAndRunningTaskGroups') uniquePendingAndRunningTaskGroups; 37 38 taskGroupSorting = ['name']; 39 @sort('uniquePendingAndRunningTaskGroups', 'taskGroupSorting') 40 sortedTaskGroups; 41 42 setUpTerminal(Terminal) { 43 this.terminal = new Terminal({ 44 fontFamily: 'monospace', 45 fontWeight: '400', 46 }); 47 window.execTerminal = this.terminal; // Issue to improve: https://github.com/hashicorp/nomad/issues/7457 48 49 this.terminal.write(ANSI_UI_GRAY_400); 50 51 if (this.sortedTaskGroups.length > 0) { 52 this.terminal.writeln('Select a task to start your session.'); 53 } else { 54 this.terminal.writeln(`There are no tasks running for this job.`); 55 } 56 } 57 58 @alias('model.allocations') allocations; 59 60 @computed( 61 'allocations.{[],@each.isActive}', 62 'allocationShortId', 63 'taskName', 64 'taskGroupName', 65 'allocation', 66 'allocation.states.@each.{name,isRunning}' 67 ) 68 get taskState() { 69 if (!this.allocations) { 70 return false; 71 } 72 73 let allocation; 74 75 if (this.allocationShortId) { 76 allocation = this.allocations.findBy('shortId', this.allocationShortId); 77 } else { 78 allocation = this.allocations.find((allocation) => 79 allocation.states 80 .filterBy('isActive') 81 .mapBy('name') 82 .includes(this.taskName) 83 ); 84 } 85 86 if (allocation) { 87 return allocation.states.find((state) => state.name === this.taskName); 88 } 89 90 return undefined; 91 } 92 93 @action 94 setTaskProperties({ allocationShortId, taskName, taskGroupName }) { 95 this.setProperties({ 96 allocationShortId, 97 taskName, 98 taskGroupName, 99 }); 100 101 if (this.taskState) { 102 this.terminal.write(ANSI_UI_GRAY_400); 103 this.terminal.writeln(''); 104 105 if (!allocationShortId) { 106 this.terminal.writeln( 107 'Multiple instances of this task are running. The allocation below was selected by random draw.' 108 ); 109 this.terminal.writeln(''); 110 } 111 112 this.terminal.writeln( 113 'Customize your command, then hit ‘return’ to run.' 114 ); 115 this.terminal.writeln(''); 116 this.terminal.write( 117 `$ nomad alloc exec -i -t -task ${escapeTaskName(taskName)} ${ 118 this.taskState.allocation.shortId 119 } ` 120 ); 121 122 this.terminal.write(ANSI_WHITE); 123 124 this.terminal.write(this.command); 125 126 if (this.commandEditorAdapter) { 127 this.commandEditorAdapter.destroy(); 128 } 129 130 this.commandEditorAdapter = new ExecCommandEditorXtermAdapter( 131 this.terminal, 132 this.openAndConnectSocket.bind(this), 133 this.command 134 ); 135 } 136 } 137 138 openAndConnectSocket(command) { 139 if (this.taskState) { 140 this.set('socketOpen', true); 141 this.set('command', command); 142 this.socket = this.sockets.getTaskStateSocket(this.taskState, command); 143 144 new ExecSocketXtermAdapter(this.terminal, this.socket, this.token.secret); 145 } else { 146 this.terminal.writeln( 147 `Failed to open a socket because task ${this.taskName} is not active.` 148 ); 149 } 150 } 151 }