120 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| 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
 |