summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrasimir Angelov <kangelov@gitlab.com>2019-09-06 17:20:05 +1200
committerKrasimir Angelov <kangelov@gitlab.com>2019-09-10 13:56:07 +1200
commit676675dc0b95194be72dfa13829b5ba06e0d1844 (patch)
tree21a2227c9ea34b715016456ef37e2f0b4eed5df2
parent8ce331c206dd97bbfc672a554afb8bc0f8039983 (diff)
downloadgitlab-ce-676675dc0b95194be72dfa13829b5ba06e0d1844.tar.gz
Add support for custom domains to the internal Pages API
Update the `/internal/pages` endpoint to return virtual domain configuration for custom domains.
-rw-r--r--app/models/pages/lookup_path.rb38
-rw-r--r--app/models/pages/virtual_domain.rb28
-rw-r--r--app/models/pages_domain.rb4
-rw-r--r--app/models/project.rb14
-rw-r--r--app/models/project_feature.rb4
-rw-r--r--lib/api/entities/internal.rb19
-rw-r--r--lib/api/internal/pages.rb7
-rw-r--r--spec/fixtures/api/schemas/internal/pages/lookup_path.json25
-rw-r--r--spec/fixtures/api/schemas/internal/pages/virtual_domain.json16
-rw-r--r--spec/models/pages/lookup_path_spec.rb64
-rw-r--r--spec/requests/api/internal/pages_spec.rb28
11 files changed, 238 insertions, 9 deletions
diff --git a/app/models/pages/lookup_path.rb b/app/models/pages/lookup_path.rb
new file mode 100644
index 00000000000..1b3183a2a43
--- /dev/null
+++ b/app/models/pages/lookup_path.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Pages
+ class LookupPath
+ def initialize(project, domain: nil)
+ @project = project
+ @domain = domain
+ end
+
+ def project_id
+ project.id
+ end
+
+ def access_control
+ project.private_pages?
+ end
+
+ def https_only
+ domain_https = domain ? domain.https? : true
+ project.pages_https_only? && domain_https
+ end
+
+ def source
+ {
+ type: 'file',
+ path: File.join(project.full_path, 'public/')
+ }
+ end
+
+ def prefix
+ '/'
+ end
+
+ private
+
+ attr_reader :project, :domain
+ end
+end
diff --git a/app/models/pages/virtual_domain.rb b/app/models/pages/virtual_domain.rb
new file mode 100644
index 00000000000..3a876dc06a2
--- /dev/null
+++ b/app/models/pages/virtual_domain.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Pages
+ class VirtualDomain
+ def initialize(projects, domain: nil)
+ @projects = projects
+ @domain = domain
+ end
+
+ def certificate
+ domain&.certificate
+ end
+
+ def key
+ domain&.key
+ end
+
+ def lookup_paths
+ projects.map do |project|
+ project.pages_lookup_path(domain: domain)
+ end.sort_by(&:prefix).reverse
+ end
+
+ private
+
+ attr_reader :projects, :domain
+ end
+end
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index a2a471074a9..22a6bae7cf7 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -185,6 +185,10 @@ class PagesDomain < ApplicationRecord
self.certificate_source = 'gitlab_provided' if key_changed?
end
+ def pages_virtual_domain
+ Pages::VirtualDomain.new([project], domain: self)
+ end
+
private
def set_verification_code
diff --git a/app/models/project.rb b/app/models/project.rb
index d948410e397..12f5da05efa 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -61,11 +61,11 @@ class Project < ApplicationRecord
cache_markdown_field :description, pipeline: :description
- delegate :feature_available?, :builds_enabled?, :wiki_enabled?,
- :merge_requests_enabled?, :issues_enabled?, :pages_enabled?, :public_pages?,
- :merge_requests_access_level, :issues_access_level, :wiki_access_level,
- :snippets_access_level, :builds_access_level, :repository_access_level,
- to: :project_feature, allow_nil: true
+ delegate :feature_available?, :builds_enabled?, :wiki_enabled?, :merge_requests_enabled?,
+ :issues_enabled?, :pages_enabled?, :public_pages?, :private_pages?,
+ :merge_requests_access_level, :issues_access_level, :wiki_access_level,
+ :snippets_access_level, :builds_access_level, :repository_access_level,
+ to: :project_feature, allow_nil: true
delegate :base_dir, :disk_path, :ensure_storage_path_exists, to: :storage
@@ -2201,6 +2201,10 @@ class Project < ApplicationRecord
members.maintainers.order_recent_sign_in.limit(ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT)
end
+ def pages_lookup_path(domain: nil)
+ Pages::LookupPath.new(self, domain: domain)
+ end
+
private
def merge_requests_allowing_collaboration(source_branch = nil)
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index 78e82955342..efa3fbcf015 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -129,6 +129,10 @@ class ProjectFeature < ApplicationRecord
pages_access_level == PUBLIC || pages_access_level == ENABLED && project.public?
end
+ def private_pages?
+ !public_pages?
+ end
+
private
# Validates builds and merge requests access level
diff --git a/lib/api/entities/internal.rb b/lib/api/entities/internal.rb
new file mode 100644
index 00000000000..8f79bd14833
--- /dev/null
+++ b/lib/api/entities/internal.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module Internal
+ module Pages
+ class LookupPath < Grape::Entity
+ expose :project_id, :access_control,
+ :source, :https_only, :prefix
+ end
+
+ class VirtualDomain < Grape::Entity
+ expose :certificate, :key
+ expose :lookup_paths, using: LookupPath
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/internal/pages.rb b/lib/api/internal/pages.rb
index 6ea048bde03..eaa434cff51 100644
--- a/lib/api/internal/pages.rb
+++ b/lib/api/internal/pages.rb
@@ -18,7 +18,12 @@ module API
namespace 'internal' do
namespace 'pages' do
get "/" do
- status :ok
+ host = PagesDomain.find_by_domain(params[:host])
+ not_found! unless host
+
+ virtual_domain = host.pages_virtual_domain
+
+ present virtual_domain, with: Entities::Internal::Pages::VirtualDomain
end
end
end
diff --git a/spec/fixtures/api/schemas/internal/pages/lookup_path.json b/spec/fixtures/api/schemas/internal/pages/lookup_path.json
new file mode 100644
index 00000000000..b2b3d3f9d0a
--- /dev/null
+++ b/spec/fixtures/api/schemas/internal/pages/lookup_path.json
@@ -0,0 +1,25 @@
+{
+ "type": "object",
+ "required": [
+ "project_id",
+ "https_only",
+ "access_control",
+ "source",
+ "prefix"
+ ],
+ "properties": {
+ "project_id": { "type": "integer" },
+ "https_only": { "type": "boolean" },
+ "access_control": { "type": "boolean" },
+ "source": { "type": "object",
+ "required": ["type", "path"],
+ "properties" : {
+ "type": { "type": "string", "enum": ["file"] },
+ "path": { "type": "string" }
+ },
+ "additionalProperties": false
+ },
+ "prefix": { "type": "string" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/internal/pages/virtual_domain.json b/spec/fixtures/api/schemas/internal/pages/virtual_domain.json
new file mode 100644
index 00000000000..02df69026b0
--- /dev/null
+++ b/spec/fixtures/api/schemas/internal/pages/virtual_domain.json
@@ -0,0 +1,16 @@
+{
+ "type": "object",
+ "required": [
+ "lookup_paths"
+ ],
+ "optional": [
+ "certificate",
+ "key"
+ ],
+ "properties": {
+ "certificate": { "type": ["string", "null"] },
+ "key": { "type": ["string", "null"] },
+ "lookup_paths": { "type": "array", "items": { "$ref": "lookup_path.json" } }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/models/pages/lookup_path_spec.rb b/spec/models/pages/lookup_path_spec.rb
new file mode 100644
index 00000000000..2146b0c9abd
--- /dev/null
+++ b/spec/models/pages/lookup_path_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Pages::LookupPath do
+ let(:project) do
+ instance_double(Project,
+ id: 12345,
+ private_pages?: true,
+ pages_https_only?: true,
+ full_path: 'the/full/path'
+ )
+ end
+
+ subject(:lookup_path) { described_class.new(project) }
+
+ describe '#project_id' do
+ it 'delegates to Project#id' do
+ expect(lookup_path.project_id).to eq(12345)
+ end
+ end
+
+ describe '#access_control' do
+ it 'delegates to Project#private_pages?' do
+ expect(lookup_path.access_control).to eq(true)
+ end
+ end
+
+ describe '#https_only' do
+ subject(:lookup_path) { described_class.new(project, domain: domain) }
+
+ context 'when no domain provided' do
+ let(:domain) { nil }
+
+ it 'delegates to Project#pages_https_only?' do
+ expect(lookup_path.https_only).to eq(true)
+ end
+ end
+
+ context 'when there is domain provided' do
+ let(:domain) { instance_double(PagesDomain, https?: false) }
+
+ it 'takes into account the https setting of the domain' do
+ expect(lookup_path.https_only).to eq(false)
+ end
+ end
+ end
+
+ describe '#source' do
+ it 'sets the source type to "file"' do
+ expect(lookup_path.source[:type]).to eq('file')
+ end
+
+ it 'sets the source path to the project full path suffixed with "public/' do
+ expect(lookup_path.source[:path]).to eq('the/full/path/public/')
+ end
+ end
+
+ describe '#prefix' do
+ it 'returns "/"' do
+ expect(lookup_path.prefix).to eq('/')
+ end
+ end
+end
diff --git a/spec/requests/api/internal/pages_spec.rb b/spec/requests/api/internal/pages_spec.rb
index 0b3c5be9c45..e1b563b92f4 100644
--- a/spec/requests/api/internal/pages_spec.rb
+++ b/spec/requests/api/internal/pages_spec.rb
@@ -43,10 +43,32 @@ describe API::Internal::Pages do
super(host, headers)
end
- it 'responds with 200 OK' do
- query_host('pages.gitlab.io')
+ context 'not existing host' do
+ it 'responds with 404 Not Found' do
+ query_host('pages.gitlab.io')
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'custom domain' do
+ let(:namespace) { create(:namespace, name: 'gitlab-org') }
+ let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') }
+ let!(:pages_domain) { create(:pages_domain, domain: 'pages.gitlab.io', project: project) }
+
+ it 'responds with the correct domain configuration' do
+ query_host('pages.gitlab.io')
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('internal/pages/virtual_domain')
+
+ expect(json_response['certificate']).to eq(pages_domain.certificate)
+ expect(json_response['key']).to eq(pages_domain.key)
- expect(response).to have_gitlab_http_status(200)
+ lookup_path = json_response['lookup_paths'][0]
+ expect(lookup_path['prefix']).to eq('/')
+ expect(lookup_path['source']['path']).to eq('gitlab-org/gitlab-ce/public/')
+ end
end
end
end