Commit 07e579ce authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'mattkasa/gitlab-195964-serverless-domain-class' into 'master'

Add Gitlab::Serverless::FunctionURI class

See merge request gitlab-org/gitlab!22733
parents f2094cb0 f205149b
......@@ -11,7 +11,7 @@ module Clusters
self.table_name = 'clusters_applications_knative'
has_one :serverless_domain_cluster, class_name: 'Serverless::DomainCluster', foreign_key: 'clusters_applications_knative_id', inverse_of: :knative
has_one :serverless_domain_cluster, class_name: '::Serverless::DomainCluster', foreign_key: 'clusters_applications_knative_id', inverse_of: :knative
include ::Clusters::Concerns::ApplicationCore
include ::Clusters::Concerns::ApplicationStatus
......
......@@ -15,5 +15,7 @@ module Serverless
format: { with: HEX_REGEXP, message: 'only allows hex characters' }
default_value_for(:uuid, allows_nil: false) { Gitlab::Serverless::Domain.generate_uuid }
delegate :domain, to: :pages_domain
end
end
# frozen_string_literal: true
module Gitlab
module Serverless
class FunctionURI < URI::HTTPS
SERVERLESS_DOMAIN_REGEXP = %r{^(?<scheme>https?://)?(?<function>[^.]+)-(?<cluster_left>\h{2})a1(?<cluster_middle>\h{10})f2(?<cluster_right>\h{2})(?<environment_id>\h+)-(?<environment_slug>[^.]+)\.(?<domain>.+)}.freeze
attr_reader :function, :cluster, :environment
def initialize(function: nil, cluster: nil, environment: nil)
initialize_required_argument(:function, function)
initialize_required_argument(:cluster, cluster)
initialize_required_argument(:environment, environment)
@host = "#{function}-#{cluster.uuid[0..1]}a1#{cluster.uuid[2..-3]}f2#{cluster.uuid[-2..-1]}#{"%x" % environment.id}-#{environment.slug}.#{cluster.domain}"
super('https', nil, host, nil, nil, nil, nil, nil, nil)
end
def self.parse(uri)
match = SERVERLESS_DOMAIN_REGEXP.match(uri)
return unless match
cluster = ::Serverless::DomainCluster.find(match[:cluster_left] + match[:cluster_middle] + match[:cluster_right])
return unless cluster
environment = ::Environment.find(match[:environment_id].to_i(16))
return unless environment&.slug == match[:environment_slug]
new(
function: match[:function],
cluster: cluster,
environment: environment
)
end
private
def initialize_required_argument(name, value)
raise ArgumentError.new("missing argument: #{name}") unless value
instance_variable_set("@#{name}".to_sym, value)
end
end
end
end
......@@ -374,5 +374,10 @@ x6zG6WoibsbsJMj70nwseUnPTBQNDP+j61RJjC/r
-----END EC PRIVATE KEY-----'
end
end
trait :instance_serverless do
wildcard { true }
domain_type { :instance }
end
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :serverless_domain_cluster, class: 'Serverless::DomainCluster' do
factory :serverless_domain_cluster, class: '::Serverless::DomainCluster' do
pages_domain { create(:pages_domain) }
knative { create(:clusters_applications_knative) }
creator { create(:user) }
......
......@@ -6,7 +6,7 @@ describe Gitlab::Prometheus::Queries::KnativeInvocationQuery do
include PrometheusHelpers
let(:project) { create(:project) }
let(:serverless_func) { Serverless::Function.new(project, 'test-name', 'test-ns') }
let(:serverless_func) { ::Serverless::Function.new(project, 'test-name', 'test-ns') }
let(:client) { double('prometheus_client') }
subject { described_class.new(client) }
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Serverless::FunctionURI do
let(:function) { 'test-function' }
let(:domain) { 'serverless.gitlab.io' }
let(:pages_domain) { create(:pages_domain, :instance_serverless, domain: domain) }
let!(:cluster) { create(:serverless_domain_cluster, uuid: 'abcdef12345678', pages_domain: pages_domain) }
let(:valid_cluster) { 'aba1cdef123456f278' }
let(:invalid_cluster) { 'aba1cdef123456f178' }
let!(:environment) { create(:environment, name: 'test') }
let(:valid_uri) { "https://#{function}-#{valid_cluster}#{"%x" % environment.id}-#{environment.slug}.#{domain}" }
let(:valid_fqdn) { "#{function}-#{valid_cluster}#{"%x" % environment.id}-#{environment.slug}.#{domain}" }
let(:invalid_uri) { "https://#{function}-#{invalid_cluster}#{"%x" % environment.id}-#{environment.slug}.#{domain}" }
shared_examples 'a valid FunctionURI class' do
describe '#to_s' do
it 'matches valid URI' do
expect(subject.to_s).to eq valid_uri
end
end
describe '#function' do
it 'returns function' do
expect(subject.function).to eq function
end
end
describe '#cluster' do
it 'returns cluster' do
expect(subject.cluster).to eq cluster
end
end
describe '#environment' do
it 'returns environment' do
expect(subject.environment).to eq environment
end
end
end
describe '.new' do
context 'with valid arguments' do
subject { described_class.new(function: function, cluster: cluster, environment: environment) }
it_behaves_like 'a valid FunctionURI class'
end
context 'with invalid arguments' do
subject { described_class.new(function: function, environment: environment) }
it 'raises an exception' do
expect { subject }.to raise_error(ArgumentError)
end
end
end
describe '.parse' do
context 'with valid URI' do
subject { described_class.parse(valid_uri) }
it_behaves_like 'a valid FunctionURI class'
end
context 'with valid FQDN' do
subject { described_class.parse(valid_fqdn) }
it_behaves_like 'a valid FunctionURI class'
end
context 'with invalid URI' do
subject { described_class.parse(invalid_uri) }
it 'returns nil' do
expect(subject).to be_nil
end
end
end
end
......@@ -17,7 +17,7 @@ describe Clusters::Applications::Knative do
end
describe 'associations' do
it { is_expected.to have_one(:serverless_domain_cluster).class_name('Serverless::DomainCluster').with_foreign_key('clusters_applications_knative_id').inverse_of(:knative) }
it { is_expected.to have_one(:serverless_domain_cluster).class_name('::Serverless::DomainCluster').with_foreign_key('clusters_applications_knative_id').inverse_of(:knative) }
end
describe 'when cloud run is enabled' do
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
describe Serverless::DomainCluster do
describe ::Serverless::DomainCluster do
subject { create(:serverless_domain_cluster) }
describe 'validations' do
......@@ -46,4 +46,8 @@ describe Serverless::DomainCluster do
end
end
end
describe 'domain' do
it { is_expected.to respond_to(:domain) }
end
end
......@@ -2,7 +2,7 @@
require 'spec_helper'
describe Serverless::Function do
describe ::Serverless::Function do
let(:project) { create(:project) }
let(:func) { described_class.new(project, 'test', 'test-ns') }
......
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