Shell: Add toggle to execute command as root
This commit is contained in:
@ -8,7 +8,8 @@ $(document).on('turbolinks:load', function () {
|
|||||||
const executeCommand = function (command) {
|
const executeCommand = function (command) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
data: {
|
data: {
|
||||||
command: command
|
command: command,
|
||||||
|
sudo: $('#sudo').is(':checked')
|
||||||
},
|
},
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: $('#shell').data('url')
|
url: $('#shell').data('url')
|
||||||
@ -92,6 +93,12 @@ $(document).on('turbolinks:load', function () {
|
|||||||
const command = $('#command')
|
const command = $('#command')
|
||||||
command.focus();
|
command.focus();
|
||||||
command.on('keypress', handleKeyPress);
|
command.on('keypress', handleKeyPress);
|
||||||
|
|
||||||
|
const sudo = $('#sudo');
|
||||||
|
sudo.on('change', function () {
|
||||||
|
sudo.parent().toggleClass('text-muted')
|
||||||
|
command.focus();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
@ -29,7 +29,8 @@ class ExecutionEnvironmentsController < ApplicationController
|
|||||||
|
|
||||||
def execute_command
|
def execute_command
|
||||||
runner = Runner.for(current_user, @execution_environment)
|
runner = Runner.for(current_user, @execution_environment)
|
||||||
output = runner.execute_command(params[:command], raise_exception: false)
|
sudo = ActiveModel::Type::Boolean.new.cast(params[:sudo])
|
||||||
|
output = runner.execute_command(params[:command], privileged_execution: sudo, raise_exception: false)
|
||||||
render json: output.except(:messages)
|
render json: output.except(:messages)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ class Runner < ApplicationRecord
|
|||||||
@strategy.copy_files(files)
|
@strategy.copy_files(files)
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach_to_execution(command, &block)
|
def attach_to_execution(command, privileged_execution: false, &block)
|
||||||
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Starting execution with Runner #{id} for #{user_type} #{user_id}." }
|
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Starting execution with Runner #{id} for #{user_type} #{user_id}." }
|
||||||
starting_time = Time.zone.now
|
starting_time = Time.zone.now
|
||||||
begin
|
begin
|
||||||
@ -62,7 +62,7 @@ class Runner < ApplicationRecord
|
|||||||
# initializing its Runner::Connection with the given event loop. The Runner::Connection class ensures that
|
# initializing its Runner::Connection with the given event loop. The Runner::Connection class ensures that
|
||||||
# this event loop is stopped after the socket was closed.
|
# this event loop is stopped after the socket was closed.
|
||||||
event_loop = Runner::EventLoop.new
|
event_loop = Runner::EventLoop.new
|
||||||
socket = @strategy.attach_to_execution(command, event_loop, starting_time, &block)
|
socket = @strategy.attach_to_execution(command, event_loop, starting_time, privileged_execution: privileged_execution, &block)
|
||||||
event_loop.wait
|
event_loop.wait
|
||||||
raise socket.error if socket.error.present?
|
raise socket.error if socket.error.present?
|
||||||
rescue Runner::Error => e
|
rescue Runner::Error => e
|
||||||
@ -74,7 +74,7 @@ class Runner < ApplicationRecord
|
|||||||
Time.zone.now - starting_time # execution duration
|
Time.zone.now - starting_time # execution duration
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute_command(command, raise_exception: true)
|
def execute_command(command, privileged_execution: false, raise_exception: true)
|
||||||
output = {
|
output = {
|
||||||
stdout: +'',
|
stdout: +'',
|
||||||
stderr: +'',
|
stderr: +'',
|
||||||
@ -89,7 +89,7 @@ class Runner < ApplicationRecord
|
|||||||
save
|
save
|
||||||
end
|
end
|
||||||
|
|
||||||
execution_time = attach_to_execution(command) do |socket, starting_time|
|
execution_time = attach_to_execution(command, privileged_execution: privileged_execution) do |socket, starting_time|
|
||||||
socket.on :stderr do |data|
|
socket.on :stderr do |data|
|
||||||
output[:stderr] << data
|
output[:stderr] << data
|
||||||
output[:messages].push({cmd: :write, stream: :stderr, log: data, timestamp: Time.zone.now - starting_time})
|
output[:messages].push({cmd: :write, stream: :stderr, log: data, timestamp: Time.zone.now - starting_time})
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
h1 = @execution_environment
|
h1 = @execution_environment
|
||||||
|
|
||||||
#shell data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @execution_environment.permitted_execution_time) data-message-out-of-memory=t('exercises.editor.out_of_memory', memory_limit: @execution_environment.memory_limit) data-url=execute_command_execution_environment_path(@execution_environment)
|
#shell data-message-timeout=t('exercises.editor.timeout', permitted_execution_time: @execution_environment.permitted_execution_time) data-message-out-of-memory=t('exercises.editor.out_of_memory', memory_limit: @execution_environment.memory_limit) data-url=execute_command_execution_environment_path(@execution_environment)
|
||||||
.mb-3
|
label.form-label for='command' = t('execution_environments.shell.command')
|
||||||
label for='command' = t('.command')
|
.input-group.mb-3
|
||||||
|
.input-group-text.form-switch.ps-5.text-muted
|
||||||
|
input#sudo.form-check-input.mt-0 type='checkbox'
|
||||||
|
label.ms-2 for='sudo' = 'sudo'
|
||||||
input#command.form-control type='text'
|
input#command.form-control type='text'
|
||||||
pre#output data-message-no-output=t('exercises.implement.no_output', timestamp: l(Time.now, format: :short))
|
pre#output data-message-no-output=t('exercises.implement.no_output', timestamp: l(Time.now, format: :short))
|
||||||
p = t('exercises.implement.no_output_yet')
|
p = t('exercises.implement.no_output_yet')
|
||||||
|
@ -33,7 +33,7 @@ class Runner::Strategy
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach_to_execution(_command, _event_loop, _starting_time)
|
def attach_to_execution(_command, _event_loop, _starting_time, _privileged_execution:)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ class Runner::Strategy::DockerContainerPool < Runner::Strategy
|
|||||||
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Finished copying files" }
|
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Finished copying files" }
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach_to_execution(command, event_loop, starting_time)
|
def attach_to_execution(command, event_loop, starting_time, _privileged_execution: false)
|
||||||
reset_inactivity_timer
|
reset_inactivity_timer
|
||||||
|
|
||||||
@command = command
|
@command = command
|
||||||
|
@ -25,7 +25,7 @@ class Runner::Strategy::Null < Runner::Strategy
|
|||||||
|
|
||||||
def copy_files(_files); end
|
def copy_files(_files); end
|
||||||
|
|
||||||
def attach_to_execution(command, event_loop, starting_time)
|
def attach_to_execution(command, event_loop, starting_time, _privileged_execution: false)
|
||||||
socket = Connection.new(nil, self, event_loop)
|
socket = Connection.new(nil, self, event_loop)
|
||||||
# We don't want to return an error if the execution environment is changed
|
# We don't want to return an error if the execution environment is changed
|
||||||
socket.status = :terminated_by_codeocean if command == ExecutionEnvironment::VALIDATION_COMMAND
|
socket.status = :terminated_by_codeocean if command == ExecutionEnvironment::VALIDATION_COMMAND
|
||||||
|
@ -134,8 +134,8 @@ class Runner::Strategy::Poseidon < Runner::Strategy
|
|||||||
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Finished copying files" }
|
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Finished copying files" }
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach_to_execution(command, event_loop, starting_time)
|
def attach_to_execution(command, event_loop, starting_time, privileged_execution: false)
|
||||||
websocket_url = execute_command(command)
|
websocket_url = execute_command(command, privileged_execution: privileged_execution)
|
||||||
socket = Connection.new(websocket_url, self, event_loop)
|
socket = Connection.new(websocket_url, self, event_loop)
|
||||||
yield(socket, starting_time)
|
yield(socket, starting_time)
|
||||||
socket
|
socket
|
||||||
@ -243,12 +243,12 @@ class Runner::Strategy::Poseidon < Runner::Strategy
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def execute_command(command)
|
def execute_command(command, privileged_execution: false)
|
||||||
url = "#{runner_url}/execute"
|
url = "#{runner_url}/execute"
|
||||||
body = {
|
body = {
|
||||||
command: command,
|
command: command,
|
||||||
timeLimit: @execution_environment.permitted_execution_time,
|
timeLimit: @execution_environment.permitted_execution_time,
|
||||||
privilegedExecution: @execution_environment.privileged_execution,
|
privilegedExecution: privileged_execution || @execution_environment.privileged_execution,
|
||||||
}
|
}
|
||||||
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Preparing command execution at #{url}: #{command}" }
|
Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Preparing command execution at #{url}: #{command}" }
|
||||||
response = self.class.http_connection.post url, body.to_json
|
response = self.class.http_connection.post url, body.to_json
|
||||||
|
Reference in New Issue
Block a user