2018-10-22 03:00:50 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-04-27 07:01:54 -04:00
|
|
|
module Gitlab
|
|
|
|
class PagesClient
|
|
|
|
class << self
|
|
|
|
attr_reader :certificate, :token
|
|
|
|
|
|
|
|
def call(service, rpc, request, timeout: nil)
|
|
|
|
kwargs = request_kwargs(timeout)
|
|
|
|
stub(service).__send__(rpc, request, kwargs) # rubocop:disable GitlabSecurity/PublicSend
|
|
|
|
end
|
|
|
|
|
|
|
|
# This function is not thread-safe. Call it from an initializer only.
|
|
|
|
def read_or_create_token
|
|
|
|
@token = read_token
|
|
|
|
rescue Errno::ENOENT
|
|
|
|
# TODO: uncomment this when omnibus knows how to write the token file for us
|
|
|
|
# https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/2466
|
|
|
|
#
|
|
|
|
# write_token(SecureRandom.random_bytes(64))
|
|
|
|
#
|
|
|
|
# # Read from disk in case someone else won the race and wrote the file
|
|
|
|
# # before us. If this fails again let the exception bubble up.
|
|
|
|
# @token = read_token
|
|
|
|
end
|
|
|
|
|
|
|
|
# This function is not thread-safe. Call it from an initializer only.
|
|
|
|
def load_certificate
|
|
|
|
cert_path = config.certificate
|
|
|
|
return unless cert_path.present?
|
|
|
|
|
|
|
|
@certificate = File.read(cert_path)
|
|
|
|
end
|
|
|
|
|
|
|
|
def ping
|
|
|
|
request = Grpc::Health::V1::HealthCheckRequest.new
|
|
|
|
call(:health_check, :check, request, timeout: 5.seconds)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def request_kwargs(timeout)
|
|
|
|
encoded_token = Base64.strict_encode64(token.to_s)
|
|
|
|
metadata = {
|
|
|
|
'authorization' => "Bearer #{encoded_token}"
|
|
|
|
}
|
|
|
|
|
|
|
|
result = { metadata: metadata }
|
|
|
|
|
|
|
|
return result unless timeout
|
|
|
|
|
|
|
|
# Do not use `Time.now` for deadline calculation, since it
|
|
|
|
# will be affected by Timecop in some tests, but grpc's c-core
|
|
|
|
# uses system time instead of timecop's time, so tests will fail
|
|
|
|
# `Time.at(Process.clock_gettime(Process::CLOCK_REALTIME))` will
|
|
|
|
# circumvent timecop
|
|
|
|
deadline = Time.at(Process.clock_gettime(Process::CLOCK_REALTIME)) + timeout
|
|
|
|
result[:deadline] = deadline
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def stub(name)
|
|
|
|
stub_class(name).new(address, grpc_creds)
|
|
|
|
end
|
|
|
|
|
|
|
|
def stub_class(name)
|
|
|
|
if name == :health_check
|
|
|
|
Grpc::Health::V1::Health::Stub
|
|
|
|
else
|
|
|
|
# TODO use pages namespace
|
|
|
|
Gitaly.const_get(name.to_s.camelcase.to_sym).const_get(:Stub)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def address
|
|
|
|
addr = config.address
|
|
|
|
addr = addr.sub(%r{^tcp://}, '') if URI(addr).scheme == 'tcp'
|
|
|
|
addr
|
|
|
|
end
|
|
|
|
|
|
|
|
def grpc_creds
|
|
|
|
if address.start_with?('unix:')
|
|
|
|
:this_channel_is_insecure
|
|
|
|
elsif @certificate
|
|
|
|
GRPC::Core::ChannelCredentials.new(@certificate)
|
|
|
|
else
|
|
|
|
# Use system certificate pool
|
|
|
|
GRPC::Core::ChannelCredentials.new
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def config
|
|
|
|
Gitlab.config.pages.admin
|
|
|
|
end
|
|
|
|
|
|
|
|
def read_token
|
|
|
|
File.read(token_path)
|
|
|
|
end
|
|
|
|
|
|
|
|
def token_path
|
|
|
|
Rails.root.join('.gitlab_pages_secret').to_s
|
|
|
|
end
|
|
|
|
|
|
|
|
def write_token(new_token)
|
|
|
|
Tempfile.open(File.basename(token_path), File.dirname(token_path), encoding: 'ascii-8bit') do |f|
|
|
|
|
f.write(new_token)
|
|
|
|
f.close
|
|
|
|
File.link(f.path, token_path)
|
|
|
|
end
|
|
|
|
rescue Errno::EACCES => ex
|
|
|
|
# TODO stop rescuing this exception in GitLab 11.0 https://gitlab.com/gitlab-org/gitlab-ce/issues/45672
|
|
|
|
Rails.logger.error("Could not write pages admin token file: #{ex}")
|
|
|
|
rescue Errno::EEXIST
|
|
|
|
# Another process wrote the token file concurrently with us. Use their token, not ours.
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|