2018-09-26 03:45:43 +00:00
# frozen_string_literal: true
2017-05-16 11:41:15 +00:00
class Projects :: JobsController < Projects :: ApplicationController
2018-03-02 21:19:17 +00:00
include SendFileUpload
2018-08-26 15:57:51 +00:00
include ContinueParams
2018-03-02 21:19:17 +00:00
2021-12-10 18:14:42 +00:00
before_action :find_job_as_build , except : [ :index , :play , :show ]
before_action :find_job_as_processable , only : [ :play , :show ]
2020-12-10 15:10:12 +00:00
before_action :authorize_read_build_trace! , only : [ :trace , :raw ]
2018-07-05 13:55:10 +00:00
before_action :authorize_read_build!
2017-05-05 11:24:07 +00:00
before_action :authorize_update_build! ,
2021-07-26 12:10:08 +00:00
except : [ :index , :show , :status , :raw , :trace , :erase , :cancel , :unschedule ]
2017-11-06 13:20:44 +00:00
before_action :authorize_erase_build! , only : [ :erase ]
2018-12-17 18:22:03 +00:00
before_action :authorize_use_build_terminal! , only : [ :terminal , :terminal_websocket_authorize ]
2018-07-05 13:55:10 +00:00
before_action :verify_api_request! , only : :terminal_websocket_authorize
2020-05-25 15:07:58 +00:00
before_action :authorize_create_proxy_build! , only : :proxy_websocket_authorize
before_action :verify_proxy_request! , only : :proxy_websocket_authorize
2021-04-19 18:09:09 +00:00
before_action :push_jobs_table_vue , only : [ :index ]
2017-05-05 11:24:07 +00:00
2021-07-12 18:09:09 +00:00
before_action do
push_frontend_feature_flag ( :infinitely_collapsible_sections , @project , default_enabled : :yaml )
end
2016-02-08 07:51:10 +00:00
layout 'project'
2015-10-07 13:24:32 +00:00
2020-10-08 18:08:32 +00:00
feature_category :continuous_integration
2015-10-14 10:15:03 +00:00
def index
2019-11-26 00:06:28 +00:00
# We need all builds for tabs counters
2020-03-14 00:09:30 +00:00
@all_builds = Ci :: JobsFinder . new ( current_user : current_user , project : @project ) . execute
2019-11-26 00:06:28 +00:00
2015-10-14 10:15:03 +00:00
@scope = params [ :scope ]
2020-03-14 00:09:30 +00:00
@builds = Ci :: JobsFinder . new ( current_user : current_user , project : @project , params : params ) . execute
2019-11-26 00:06:28 +00:00
@builds = @builds . eager_load_everything
2018-01-11 13:22:52 +00:00
@builds = @builds . page ( params [ :page ] ) . per ( 30 ) . without_count
2015-10-14 10:15:03 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2015-10-06 15:11:10 +00:00
def show
2017-05-23 15:10:07 +00:00
respond_to do | format |
format . html
format . json do
Gitlab :: PollingInterval . set_header ( response , interval : 10_000 )
render json : BuildSerializer
. new ( project : @project , current_user : @current_user )
2021-09-22 18:11:13 +00:00
. represent ( @build . present ( current_user : current_user ) , { } , BuildDetailsEntity )
2017-05-23 15:10:07 +00:00
end
end
2015-10-06 15:11:10 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-10-06 15:11:10 +00:00
2016-05-09 16:59:45 +00:00
def trace
2021-01-06 03:10:22 +00:00
@build . trace . being_watched! if @build . running?
if @build . has_trace?
@build . trace . read do | stream |
respond_to do | format |
format . json do
build_trace = Ci :: BuildTrace . new (
build : @build ,
stream : stream ,
state : params [ :state ] )
render json : BuildTraceSerializer
. new ( project : @project , current_user : @current_user )
. represent ( build_trace )
end
2017-04-06 16:20:27 +00:00
end
2016-05-09 16:59:45 +00:00
end
2021-01-06 03:10:22 +00:00
else
head :no_content
2016-05-09 16:59:45 +00:00
end
end
2015-10-07 13:24:32 +00:00
def retry
2017-04-28 09:38:32 +00:00
return respond_422 unless @build . retryable?
2015-10-07 13:24:32 +00:00
2016-06-10 21:36:54 +00:00
build = Ci :: Build . retry ( @build , current_user )
2015-11-03 10:44:07 +00:00
redirect_to build_path ( build )
2015-10-07 13:24:32 +00:00
end
2016-07-16 16:39:58 +00:00
def play
2017-04-28 09:38:32 +00:00
return respond_422 unless @build . playable?
2016-07-16 16:39:58 +00:00
2020-10-13 09:08:27 +00:00
job = @build . play ( current_user , play_params [ :job_variables_attributes ] )
if job . is_a? ( Ci :: Bridge )
redirect_to pipeline_path ( job . pipeline )
else
redirect_to build_path ( job )
end
2016-07-16 16:39:58 +00:00
end
2015-10-07 13:24:32 +00:00
def cancel
2021-07-26 12:10:08 +00:00
service_response = Ci :: BuildCancelService . new ( @build , current_user ) . execute
2017-04-28 09:38:32 +00:00
2021-07-26 12:10:08 +00:00
if service_response . success?
destination = continue_params [ :to ] . presence || builds_project_pipeline_path ( @project , @build . pipeline . id )
redirect_to destination
elsif service_response . http_status == :forbidden
access_denied!
2018-08-26 15:57:51 +00:00
else
2021-07-26 12:10:08 +00:00
head service_response . http_status
2018-08-26 15:57:51 +00:00
end
2015-10-07 13:24:32 +00:00
end
2018-09-18 07:12:13 +00:00
def unschedule
2021-07-26 12:10:08 +00:00
service_response = Ci :: BuildUnscheduleService . new ( @build , current_user ) . execute
2018-09-18 07:12:13 +00:00
2021-07-26 12:10:08 +00:00
if service_response . success?
redirect_to build_path ( @build )
elsif service_response . http_status == :forbidden
access_denied!
else
head service_response . http_status
end
2018-09-18 07:12:13 +00:00
end
2016-02-08 12:53:30 +00:00
def status
2017-03-03 06:59:25 +00:00
render json : BuildSerializer
2017-05-09 04:15:34 +00:00
. new ( project : @project , current_user : @current_user )
2021-09-22 18:11:13 +00:00
. represent_status ( @build . present ( current_user : current_user ) )
2016-02-08 12:53:30 +00:00
end
2016-02-08 07:57:09 +00:00
2016-02-01 10:59:05 +00:00
def erase
2017-04-28 09:38:32 +00:00
if @build . erase ( erased_by : current_user )
2017-06-29 17:06:35 +00:00
redirect_to project_job_path ( project , @build ) ,
2019-03-27 16:52:52 +00:00
notice : _ ( " Job has been successfully erased! " )
2017-04-28 09:38:32 +00:00
else
respond_422
end
2016-01-22 14:29:02 +00:00
end
2016-04-16 21:32:18 +00:00
def raw
2021-10-29 12:14:45 +00:00
if @build . trace . archived_trace_exist?
2018-12-06 21:22:39 +00:00
workhorse_set_content_type!
2021-10-29 12:14:45 +00:00
send_upload ( @build . job_artifacts_trace . file ,
2018-04-03 12:30:14 +00:00
send_params : raw_send_params ,
redirect_params : raw_redirect_params )
else
2020-10-13 09:08:27 +00:00
@build . trace . read do | stream |
2018-04-03 12:30:14 +00:00
if stream . file?
2018-12-06 21:22:39 +00:00
workhorse_set_content_type!
2018-04-03 12:30:14 +00:00
send_file stream . path , type : 'text/plain; charset=utf-8' , disposition : 'inline'
else
2018-12-06 21:22:39 +00:00
# In this case we can't use workhorse_set_content_type! and let
# Workhorse handle the response because the data is streamed directly
# to the user but, because we have the trace content, we can calculate
# the proper content type and disposition here.
raw_data = stream . raw
send_data raw_data , type : 'text/plain; charset=utf-8' , disposition : raw_trace_content_disposition ( raw_data ) , filename : 'job.log'
2018-04-03 12:30:14 +00:00
end
2017-04-06 16:20:27 +00:00
end
2016-04-16 21:32:18 +00:00
end
end
2018-07-05 13:55:10 +00:00
def terminal
end
# GET .../terminal.ws : implemented in gitlab-workhorse
def terminal_websocket_authorize
set_workhorse_internal_api_content_type
2019-04-04 18:32:02 +00:00
render json : Gitlab :: Workhorse . channel_websocket ( @build . terminal_specification )
2018-07-05 13:55:10 +00:00
end
2020-05-25 15:07:58 +00:00
def proxy_websocket_authorize
render json : proxy_websocket_service ( build_service_specification )
end
2015-10-06 15:11:10 +00:00
private
2020-12-10 15:10:12 +00:00
def authorize_read_build_trace!
return if can? ( current_user , :read_build_trace , @build )
msg = _ (
" You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. " \
" If you need to view this job log, a project maintainer must add you to the project with developer permissions or higher. "
)
return access_denied! ( msg ) if @build . debug_mode?
access_denied! ( _ ( 'The current user is not authorized to access the job log.' ) )
end
2017-05-05 11:24:07 +00:00
def authorize_update_build!
2020-10-13 09:08:27 +00:00
return access_denied! unless can? ( current_user , :update_build , @build )
2017-05-05 11:24:07 +00:00
end
2017-11-06 13:20:44 +00:00
def authorize_erase_build!
2020-10-13 09:08:27 +00:00
return access_denied! unless can? ( current_user , :erase_build , @build )
2017-11-06 13:20:44 +00:00
end
2018-07-05 13:55:10 +00:00
def authorize_use_build_terminal!
2020-10-13 09:08:27 +00:00
return access_denied! unless can? ( current_user , :create_build_terminal , @build )
2018-07-05 13:55:10 +00:00
end
2020-05-25 15:07:58 +00:00
def authorize_create_proxy_build!
2020-10-13 09:08:27 +00:00
return access_denied! unless can? ( current_user , :create_build_service_proxy , @build )
2020-05-25 15:07:58 +00:00
end
2018-07-05 13:55:10 +00:00
def verify_api_request!
Gitlab :: Workhorse . verify_api_request! ( request . headers )
end
2020-05-25 15:07:58 +00:00
def verify_proxy_request!
verify_api_request!
set_workhorse_internal_api_content_type
end
2018-04-03 12:30:14 +00:00
def raw_send_params
{ type : 'text/plain; charset=utf-8' , disposition : 'inline' }
end
def raw_redirect_params
{ query : { 'response-content-type' = > 'text/plain; charset=utf-8' , 'response-content-disposition' = > 'inline' } }
end
2019-07-29 07:43:10 +00:00
def play_params
params . permit ( job_variables_attributes : % i [ key secret_value ] )
end
2020-10-13 09:08:27 +00:00
def find_job_as_build
@build = project . builds . find ( params [ :id ] )
2015-10-06 15:11:10 +00:00
end
2015-10-07 13:24:32 +00:00
2020-10-13 09:08:27 +00:00
def find_job_as_processable
2020-12-03 03:09:27 +00:00
@build = project . processables . find ( params [ :id ] )
2020-10-13 09:08:27 +00:00
end
2015-10-07 13:24:32 +00:00
def build_path ( build )
2017-06-29 17:06:35 +00:00
project_job_path ( build . project , build )
2015-10-07 13:24:32 +00:00
end
2018-12-06 21:22:39 +00:00
def raw_trace_content_disposition ( raw_data )
2021-03-25 06:09:02 +00:00
mime_type = Gitlab :: Utils :: MimeType . from_string ( raw_data )
2018-12-06 21:22:39 +00:00
# if mime_type is nil can also represent 'text/plain'
2021-03-25 06:09:02 +00:00
return 'inline' if mime_type . nil? || mime_type == 'text/plain'
2018-12-06 21:22:39 +00:00
'attachment'
end
2019-09-13 13:26:31 +00:00
2020-05-25 15:07:58 +00:00
def build_service_specification
2020-10-13 09:08:27 +00:00
@build . service_specification ( service : params [ 'service' ] ,
port : params [ 'port' ] ,
path : params [ 'path' ] ,
subprotocols : proxy_subprotocol )
2020-05-25 15:07:58 +00:00
end
def proxy_subprotocol
# This will allow to reuse the same subprotocol set
# in the original websocket connection
request . headers [ 'HTTP_SEC_WEBSOCKET_PROTOCOL' ] . presence || :: Ci :: BuildRunnerSession :: TERMINAL_SUBPROTOCOL
end
# This method provides the information to Workhorse
# about the service we want to proxy to.
# For security reasons, in case this operation is started by JS,
# it's important to use only sourced GitLab JS code
def proxy_websocket_service ( service )
service [ :url ] = :: Gitlab :: UrlHelpers . as_wss ( service [ :url ] )
:: Gitlab :: Workhorse . channel_websocket ( service )
end
2021-04-19 18:09:09 +00:00
def push_jobs_table_vue
push_frontend_feature_flag ( :jobs_table_vue , @project , default_enabled : :yaml )
end
2020-05-25 15:07:58 +00:00
end