diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/pages/projects/jobs/terminal/index.js | 3 | ||||
-rw-r--r-- | app/controllers/projects/jobs_controller.rb | 22 | ||||
-rw-r--r-- | app/models/ci/build.rb | 14 | ||||
-rw-r--r-- | app/models/ci/build_runner_session.rb | 25 | ||||
-rw-r--r-- | app/policies/ci/build_policy.rb | 6 | ||||
-rw-r--r-- | app/services/ci/register_job_service.rb | 4 | ||||
-rw-r--r-- | app/views/projects/jobs/_sidebar.html.haml | 4 | ||||
-rw-r--r-- | app/views/projects/jobs/terminal.html.haml | 11 |
8 files changed, 86 insertions, 3 deletions
diff --git a/app/assets/javascripts/pages/projects/jobs/terminal/index.js b/app/assets/javascripts/pages/projects/jobs/terminal/index.js new file mode 100644 index 00000000000..7129e24cee1 --- /dev/null +++ b/app/assets/javascripts/pages/projects/jobs/terminal/index.js @@ -0,0 +1,3 @@ +import initTerminal from '~/terminal/'; + +document.addEventListener('DOMContentLoaded', initTerminal); diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 02cac862c3d..e69faae754a 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -2,11 +2,12 @@ class Projects::JobsController < Projects::ApplicationController include SendFileUpload before_action :build, except: [:index, :cancel_all] - before_action :authorize_read_build!, - only: [:index, :show, :status, :raw, :trace] + before_action :authorize_read_build! before_action :authorize_update_build!, except: [:index, :show, :status, :raw, :trace, :cancel_all, :erase] before_action :authorize_erase_build!, only: [:erase] + before_action :authorize_use_build_terminal!, only: [:terminal, :terminal_workhorse_authorize] + before_action :verify_api_request!, only: :terminal_websocket_authorize layout 'project' @@ -134,6 +135,15 @@ class Projects::JobsController < Projects::ApplicationController end end + def terminal + end + + # GET .../terminal.ws : implemented in gitlab-workhorse + def terminal_websocket_authorize + set_workhorse_internal_api_content_type + render json: Gitlab::Workhorse.terminal_websocket(@build.terminal_specification) + end + private def authorize_update_build! @@ -144,6 +154,14 @@ class Projects::JobsController < Projects::ApplicationController return access_denied! unless can?(current_user, :erase_build, build) end + def authorize_use_build_terminal! + return access_denied! unless can?(current_user, :create_build_terminal, build) + end + + def verify_api_request! + Gitlab::Workhorse.verify_api_request!(request.headers) + end + def raw_send_params { type: 'text/plain; charset=utf-8', disposition: 'inline' } end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 41446946a5e..bf93a2caf72 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -27,7 +27,13 @@ module Ci has_one :job_artifacts_trace, -> { where(file_type: Ci::JobArtifact.file_types[:trace]) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id has_one :metadata, class_name: 'Ci::BuildMetadata' + has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, inverse_of: :build + + accepts_nested_attributes_for :runner_session + delegate :timeout, to: :metadata, prefix: true, allow_nil: true + delegate :url, to: :runner_session, prefix: true, allow_nil: true + delegate :terminal_specification, to: :runner_session, allow_nil: true delegate :gitlab_deploy_token, to: :project ## @@ -174,6 +180,10 @@ module Ci after_transition pending: :running do |build| build.ensure_metadata.update_timeout_state end + + after_transition running: any do |build| + Ci::BuildRunnerSession.where(build: build).delete_all + end end def ensure_metadata @@ -584,6 +594,10 @@ module Ci super(options).merge(when: read_attribute(:when)) end + def has_terminal? + running? && runner_session_url.present? + end + private def update_artifacts_size diff --git a/app/models/ci/build_runner_session.rb b/app/models/ci/build_runner_session.rb new file mode 100644 index 00000000000..6f3be31d8e1 --- /dev/null +++ b/app/models/ci/build_runner_session.rb @@ -0,0 +1,25 @@ +module Ci + # The purpose of this class is to store Build related runner session. + # Data will be removed after transitioning from running to any state. + class BuildRunnerSession < ActiveRecord::Base + extend Gitlab::Ci::Model + + self.table_name = 'ci_builds_runner_session' + + belongs_to :build, class_name: 'Ci::Build', inverse_of: :runner_session + + validates :build, presence: true + validates :url, url: { protocols: %w(https) } + + def terminal_specification + return {} unless url.present? + + { + subprotocols: ['terminal.gitlab.com'].freeze, + url: "#{url}/exec".sub("https://", "wss://"), + headers: { Authorization: authorization.presence }.compact, + ca_pem: certificate.presence + } + end + end +end diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb index 1c0cc7425ec..75c7e529902 100644 --- a/app/policies/ci/build_policy.rb +++ b/app/policies/ci/build_policy.rb @@ -18,6 +18,10 @@ module Ci @subject.project.branch_allows_collaboration?(@user, @subject.ref) end + condition(:terminal, scope: :subject) do + @subject.has_terminal? + end + rule { protected_ref }.policy do prevent :update_build prevent :erase_build @@ -29,5 +33,7 @@ module Ci enable :update_build enable :update_commit_status end + + rule { can?(:update_build) & terminal }.enable :create_build_terminal end end diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb index c0dce45e2e7..6eb1c4f52de 100644 --- a/app/services/ci/register_job_service.rb +++ b/app/services/ci/register_job_service.rb @@ -13,7 +13,7 @@ module Ci @runner = runner end - def execute + def execute(params = {}) builds = if runner.instance_type? builds_for_shared_runner @@ -41,6 +41,8 @@ module Ci # with StateMachines::InvalidTransition or StaleObjectError when doing run! or save method. begin build.runner_id = runner.id + build.runner_session_attributes = params[:session] if params[:session].present? + build.run! register_success(build) diff --git a/app/views/projects/jobs/_sidebar.html.haml b/app/views/projects/jobs/_sidebar.html.haml index 8d890d19278..b88fe47726d 100644 --- a/app/views/projects/jobs/_sidebar.html.haml +++ b/app/views/projects/jobs/_sidebar.html.haml @@ -1,6 +1,10 @@ %aside.right-sidebar.right-sidebar-expanded.build-sidebar.js-build-sidebar.js-right-sidebar{ data: { "offset-top" => "101", "spy" => "affix" } } .sidebar-container .blocks-container + - if can?(current_user, :create_build_terminal, @build) + .block + = link_to terminal_project_job_path(@project, @build), class: 'terminal-button pull-right btn visible-md-block visible-lg-block', title: 'Terminal' do + Terminal #js-details-block-vue{ data: { can_user_retry: can?(current_user, :update_build, @build) && @build.retryable? } } diff --git a/app/views/projects/jobs/terminal.html.haml b/app/views/projects/jobs/terminal.html.haml new file mode 100644 index 00000000000..efea666a4d9 --- /dev/null +++ b/app/views/projects/jobs/terminal.html.haml @@ -0,0 +1,11 @@ +- @no_container = true +- add_to_breadcrumbs 'Jobs', project_jobs_path(@project) +- add_to_breadcrumbs "##{@build.id}", project_job_path(@project, @build) +- breadcrumb_title 'Terminal' +- page_title 'Terminal', "#{@build.name} (##{@build.id})", 'Jobs' + +- content_for :page_specific_javascripts do + = stylesheet_link_tag "xterm/xterm" + +.terminal-container{ class: container_class } + #terminal{ data: { project_path: terminal_project_job_path(@project, @build, format: :ws) } } |