# frozen_string_literal: true module Gitlab module Kas class Client TIMEOUT = 2.seconds.freeze JWT_AUDIENCE = 'gitlab-kas' STUB_CLASSES = { agent_tracker: Gitlab::Agent::AgentTracker::Rpc::AgentTracker::Stub, configuration_project: Gitlab::Agent::ConfigurationProject::Rpc::ConfigurationProject::Stub }.freeze ConfigurationError = Class.new(StandardError) def initialize raise ConfigurationError, 'GitLab KAS is not enabled' unless Gitlab::Kas.enabled? raise ConfigurationError, 'KAS internal URL is not configured' unless Gitlab::Kas.internal_url.present? end def get_connected_agents(project:) request = Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsRequest.new(project_id: project.id) stub_for(:agent_tracker) .get_connected_agents(request, metadata: metadata) .agents .to_a end def list_agent_config_files(project:) request = Gitlab::Agent::ConfigurationProject::Rpc::ListAgentConfigFilesRequest.new( repository: repository(project), gitaly_address: gitaly_address(project) ) stub_for(:configuration_project) .list_agent_config_files(request, metadata: metadata) .config_files .to_a end private def stub_for(service) @stubs ||= {} @stubs[service] ||= STUB_CLASSES.fetch(service).new(kas_endpoint_url, credentials, timeout: TIMEOUT) end def repository(project) gitaly_repository = project.repository.gitaly_repository Gitlab::Agent::Modserver::Repository.new(gitaly_repository.to_h) end def gitaly_address(project) connection_data = Gitlab::GitalyClient.connection_data(project.repository_storage) Gitlab::Agent::Modserver::GitalyAddress.new(connection_data) end def kas_endpoint_url Gitlab::Kas.internal_url.sub(%r{^grpcs?://}, '') end def credentials if URI(Gitlab::Kas.internal_url).scheme == 'grpcs' GRPC::Core::ChannelCredentials.new else :this_channel_is_insecure end end def metadata { 'authorization' => "bearer #{token}" } end def token JSONWebToken::HMACToken.new(Gitlab::Kas.secret).tap do |token| token.issuer = Settings.gitlab.host token.audience = JWT_AUDIENCE end.encoded end end end end