Commit de9d9fed authored by Francisco Javier López's avatar Francisco Javier López Committed by Nick Thomas

Renamed terminal_specification to channel_specification

We're moving from using terminology related to terminals when
we refer to Websockets connections in Workhorse.
It's more appropiate a concept like channel.
parent 03e9ea97
...@@ -117,7 +117,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -117,7 +117,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
terminal = environment.terminals.try(:first) terminal = environment.terminals.try(:first)
if terminal if terminal
set_workhorse_internal_api_content_type set_workhorse_internal_api_content_type
render json: Gitlab::Workhorse.terminal_websocket(terminal) render json: Gitlab::Workhorse.channel_websocket(terminal)
else else
render html: 'Not found', status: :not_found render html: 'Not found', status: :not_found
end end
......
...@@ -157,7 +157,7 @@ class Projects::JobsController < Projects::ApplicationController ...@@ -157,7 +157,7 @@ class Projects::JobsController < Projects::ApplicationController
# GET .../terminal.ws : implemented in gitlab-workhorse # GET .../terminal.ws : implemented in gitlab-workhorse
def terminal_websocket_authorize def terminal_websocket_authorize
set_workhorse_internal_api_content_type set_workhorse_internal_api_content_type
render json: Gitlab::Workhorse.terminal_websocket(@build.terminal_specification) render json: Gitlab::Workhorse.channel_websocket(@build.terminal_specification)
end end
private private
......
...@@ -6,6 +6,8 @@ module Ci ...@@ -6,6 +6,8 @@ module Ci
class BuildRunnerSession < ApplicationRecord class BuildRunnerSession < ApplicationRecord
extend Gitlab::Ci::Model extend Gitlab::Ci::Model
TERMINAL_SUBPROTOCOL = 'terminal.gitlab.com'.freeze
self.table_name = 'ci_builds_runner_session' self.table_name = 'ci_builds_runner_session'
belongs_to :build, class_name: 'Ci::Build', inverse_of: :runner_session belongs_to :build, class_name: 'Ci::Build', inverse_of: :runner_session
...@@ -14,11 +16,21 @@ module Ci ...@@ -14,11 +16,21 @@ module Ci
validates :url, url: { protocols: %w(https) } validates :url, url: { protocols: %w(https) }
def terminal_specification def terminal_specification
return {} unless url.present? wss_url = Gitlab::UrlHelpers.as_wss(self.url)
return {} unless wss_url.present?
wss_url = "#{wss_url}/exec"
channel_specification(wss_url, TERMINAL_SUBPROTOCOL)
end
private
def channel_specification(url, subprotocol)
return {} if subprotocol.blank? || url.blank?
{ {
subprotocols: ['terminal.gitlab.com'].freeze, subprotocols: Array(subprotocol),
url: "#{url}/exec".sub("https://", "wss://"), url: url,
headers: { Authorization: [authorization.presence] }.compact, headers: { Authorization: [authorization.presence] }.compact,
ca_pem: certificate.presence ca_pem: certificate.presence
} }
......
# frozen_string_literal: true
module Gitlab
class UrlHelpers
WSS_PROTOCOL = "wss".freeze
def self.as_wss(url)
return unless url.present?
URI.parse(url).tap do |uri|
uri.scheme = WSS_PROTOCOL
end.to_s
rescue URI::InvalidURIError
nil
end
end
end
...@@ -162,16 +162,16 @@ module Gitlab ...@@ -162,16 +162,16 @@ module Gitlab
] ]
end end
def terminal_websocket(terminal) def channel_websocket(channel)
details = { details = {
'Terminal' => { 'Channel' => {
'Subprotocols' => terminal[:subprotocols], 'Subprotocols' => channel[:subprotocols],
'Url' => terminal[:url], 'Url' => channel[:url],
'Header' => terminal[:headers], 'Header' => channel[:headers],
'MaxSessionTime' => terminal[:max_session_time] 'MaxSessionTime' => channel[:max_session_time]
} }
} }
details['Terminal']['CAPem'] = terminal[:ca_pem] if terminal.key?(:ca_pem) details['Channel']['CAPem'] = channel[:ca_pem] if channel.key?(:ca_pem)
details details
end end
......
...@@ -283,7 +283,7 @@ describe Projects::EnvironmentsController do ...@@ -283,7 +283,7 @@ describe Projects::EnvironmentsController do
.and_return([:fake_terminal]) .and_return([:fake_terminal])
expect(Gitlab::Workhorse) expect(Gitlab::Workhorse)
.to receive(:terminal_websocket) .to receive(:channel_websocket)
.with(:fake_terminal) .with(:fake_terminal)
.and_return(workhorse: :response) .and_return(workhorse: :response)
......
...@@ -989,7 +989,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do ...@@ -989,7 +989,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
context 'and valid id' do context 'and valid id' do
it 'returns the terminal for the job' do it 'returns the terminal for the job' do
expect(Gitlab::Workhorse) expect(Gitlab::Workhorse)
.to receive(:terminal_websocket) .to receive(:channel_websocket)
.and_return(workhorse: :response) .and_return(workhorse: :response)
get_terminal_websocket(id: job.id) get_terminal_websocket(id: job.id)
......
...@@ -94,7 +94,7 @@ describe Gitlab::Workhorse do ...@@ -94,7 +94,7 @@ describe Gitlab::Workhorse do
end end
end end
describe '.terminal_websocket' do describe '.channel_websocket' do
def terminal(ca_pem: nil) def terminal(ca_pem: nil)
out = { out = {
subprotocols: ['foo'], subprotocols: ['foo'],
...@@ -108,25 +108,25 @@ describe Gitlab::Workhorse do ...@@ -108,25 +108,25 @@ describe Gitlab::Workhorse do
def workhorse(ca_pem: nil) def workhorse(ca_pem: nil)
out = { out = {
'Terminal' => { 'Channel' => {
'Subprotocols' => ['foo'], 'Subprotocols' => ['foo'],
'Url' => 'wss://example.com/terminal.ws', 'Url' => 'wss://example.com/terminal.ws',
'Header' => { 'Authorization' => ['Token x'] }, 'Header' => { 'Authorization' => ['Token x'] },
'MaxSessionTime' => 600 'MaxSessionTime' => 600
} }
} }
out['Terminal']['CAPem'] = ca_pem if ca_pem out['Channel']['CAPem'] = ca_pem if ca_pem
out out
end end
context 'without ca_pem' do context 'without ca_pem' do
subject { described_class.terminal_websocket(terminal) } subject { described_class.channel_websocket(terminal) }
it { is_expected.to eq(workhorse) } it { is_expected.to eq(workhorse) }
end end
context 'with ca_pem' do context 'with ca_pem' do
subject { described_class.terminal_websocket(terminal(ca_pem: "foo")) } subject { described_class.channel_websocket(terminal(ca_pem: "foo")) }
it { is_expected.to eq(workhorse(ca_pem: "foo")) } it { is_expected.to eq(workhorse(ca_pem: "foo")) }
end end
......
...@@ -13,25 +13,33 @@ describe Ci::BuildRunnerSession, model: true do ...@@ -13,25 +13,33 @@ describe Ci::BuildRunnerSession, model: true do
it { is_expected.to validate_presence_of(:url).with_message('must be a valid URL') } it { is_expected.to validate_presence_of(:url).with_message('must be a valid URL') }
describe '#terminal_specification' do describe '#terminal_specification' do
let(:terminal_specification) { subject.terminal_specification } let(:specification) { subject.terminal_specification }
it 'returns terminal.gitlab.com protocol' do
expect(specification[:subprotocols]).to eq ['terminal.gitlab.com']
end
it 'returns a wss url' do
expect(specification[:url]).to start_with('wss://')
end
it 'returns empty hash if no url' do it 'returns empty hash if no url' do
subject.url = '' subject.url = ''
expect(terminal_specification).to be_empty expect(specification).to be_empty
end end
context 'when url is present' do context 'when url is present' do
it 'returns ca_pem nil if empty certificate' do it 'returns ca_pem nil if empty certificate' do
subject.certificate = '' subject.certificate = ''
expect(terminal_specification[:ca_pem]).to be_nil expect(specification[:ca_pem]).to be_nil
end end
it 'adds Authorization header if authorization is present' do it 'adds Authorization header if authorization is present' do
subject.authorization = 'whatever' subject.authorization = 'whatever'
expect(terminal_specification[:headers]).to include(Authorization: ['whatever']) expect(specification[:headers]).to include(Authorization: ['whatever'])
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment