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