GitLab wurde erfolgreich aktualisiert. Dank regelmäßiger Updates bleibt das THM GitLab sicher und Sie profitieren von den neuesten Funktionen. Danke für Ihre Geduld.

Commit 8ff73614 authored by Mayra Cabrera's avatar Mayra Cabrera

Moves domain setting to Cluster setting

Changes domain field to be on the Cluster page show, removing it from
Auto DevOps setting. Also injects the new environment variable
KUBE_INGRESS_BASE_DOMAIN into kubernetes#predefined_variables.

Migration to move the information from ProjectAutoDevops#domain
to Clusters::Cluster#domain. As well as necessary modifications to qa
selectors

Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/52363
parent 280b6f6f
......@@ -127,6 +127,7 @@ def update_params
params.require(:cluster).permit(
:enabled,
:environment_scope,
:domain,
platform_kubernetes_attributes: [
:namespace
]
......@@ -136,6 +137,7 @@ def update_params
:enabled,
:name,
:environment_scope,
:domain,
platform_kubernetes_attributes: [
:api_url,
:token,
......
......@@ -26,17 +26,6 @@ def auto_devops_warning_message(project)
end
end
# rubocop: disable CodeReuse/ActiveRecord
def cluster_ingress_ip(project)
project
.cluster_ingresses
.where("external_ip is not null")
.limit(1)
.pluck(:external_ip)
.first
end
# rubocop: enable CodeReuse/ActiveRecord
private
def missing_auto_devops_domain?(project)
......
......@@ -49,7 +49,7 @@ class Cluster < ActiveRecord::Base
validates :name, cluster_name: true
validates :cluster_type, presence: true
validates :domain, allow_nil: true, hostname: { allow_numeric_hostname: true, require_valid_tld: true }
validates :domain, allow_blank: true, hostname: { allow_numeric_hostname: true, require_valid_tld: true }
validate :restrict_modification, on: :update
validate :no_groups, unless: :group_type?
......@@ -65,6 +65,7 @@ class Cluster < ActiveRecord::Base
delegate :available?, to: :application_ingress, prefix: true, allow_nil: true
delegate :available?, to: :application_prometheus, prefix: true, allow_nil: true
delegate :available?, to: :application_knative, prefix: true, allow_nil: true
delegate :external_ip, to: :application_ingress, prefix: true, allow_nil: true
enum cluster_type: {
instance_type: 1,
......@@ -193,8 +194,24 @@ def allow_user_defined_namespace?
project_type?
end
def has_domain?
domain.present? || instance_domain.present?
end
def predefined_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless has_domain?
variables.append(key: 'KUBE_INGRESS_BASE_DOMAIN', value: domain.presence || instance_domain)
end
end
private
def instance_domain
Gitlab::CurrentSettings.auto_devops_domain
end
def restrict_modification
if provider&.on_creation?
errors.add(:base, "cannot modify during creation")
......
......@@ -98,6 +98,8 @@ def predefined_variables(project:)
.append(key: 'KUBE_NAMESPACE', value: actual_namespace)
.append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true)
end
variables.concat(cluster.predefined_variables)
end
end
......
......@@ -24,6 +24,9 @@ def has_domain?
domain.present? || instance_domain.present?
end
# From 11.8, AUTO_DEVOPS_DOMAIN has been replaced by KUBE_INGRESS_BASE_DOMAIN.
# See Clusters::Cluster#predefined_variables and https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24580
# for more info. Support for AUTO_DEVOPS_DOMAIN support will be dropped on 12.0.
def predefined_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
if has_domain?
......
......@@ -20,12 +20,28 @@
.form-text.text-muted= s_("ClusterIntegration|Choose which of your environments will use this cluster.")
- else
= text_field_tag :environment_scope, '*', class: 'col-md-6 form-control disabled', placeholder: s_('ClusterIntegration|Environment scope'), disabled: true
- environment_scope_url = 'https://docs.gitlab.com/ee/user/project/clusters/#setting-the-environment-scope-premium'
- environment_scope_url = 'https://docs.gitlab.com/ee/user/project/clusters/#base-domain'
- environment_scope_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: environment_scope_url }
.form-text.text-muted
%code *
= s_("ClusterIntegration| is the default environment scope for this cluster. This means that all jobs, regardless of their environment, will use this cluster. %{environment_scope_start}More information%{environment_scope_end}").html_safe % { environment_scope_start: environment_scope_start, environment_scope_end: '</a>'.html_safe }
.form-group
%h5= s_('ClusterIntegration|Base domain')
= field.text_field :domain, class: 'col-md-6 form-control js-select-on-focus'
.form-text.text-muted
- if @cluster.application_ingress_external_ip.present?
- auto_devops_url = 'https://docs.gitlab.com/ee/topics/autodevops/'
- auto_devops_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: auto_devops_url }
= s_('ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured to the Ingress IP Address below.').html_safe % { auto_devops_start: auto_devops_start, auto_devops_end: '</a>'.html_safe }
= s_('ClusterIntegration|Alternatively')
%code #{@cluster.application_ingress_external_ip}.nip.io
- custom_domain_url = 'https://docs.gitlab.com/ee/user/project/clusters/#pointing-your-dns-at-the-cluster-ip'
- custom_domain_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: custom_domain_url }
= s_('ClusterIntegration| can be used instead of a custom domain. %{custom_domain_start}More information%{custom_domain_end}').html_safe % { custom_domain_start: custom_domain_start, custom_domain_end: '</a>'.html_safe }
- else
= s_('ClusterIntegration|Before setting a domain, you must first install Ingress on your cluster below.')
- if can?(current_user, :update_cluster, @cluster)
.form-group
= field.submit _('Save changes'), class: 'btn btn-success'
......@@ -21,15 +21,10 @@
= s_('CICD|The Auto DevOps pipeline will run if no alternative CI configuration file is found.')
= link_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank'
.card-footer.js-extra-settings{ class: @project.auto_devops_enabled? || 'hidden' }
= form.label :domain do
%strong= _('Domain')
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
.form-text.text-muted
= s_('CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.')
- if cluster_ingress_ip = cluster_ingress_ip(@project)
= s_('%{nip_domain} can be used as an alternative to a custom domain.').html_safe % { nip_domain: "<code>#{cluster_ingress_ip}.nip.io</code>".html_safe }
= link_to icon('question-circle'), help_page_path('topics/autodevops/index.md', anchor: 'auto-devops-base-domain'), target: '_blank'
%p.settings-message.text-center
- kubernetes_cluster_link = 'https://docs.gitlab.com/ee/user/project/clusters/'
- kubernetes_cluster_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: kubernetes_cluster_link }
= s_('CICD|You must add a %{kubernetes_cluster_start}Kubernetes cluster integration%{kubernetes_cluster_end} to this project with a domain in order for your deployment strategy to work correctly.').html_safe % { kubernetes_cluster_start: kubernetes_cluster_start, kubernetes_cluster_end: '</a>'.html_safe }
%label.prepend-top-10
%strong= s_('CICD|Deployment strategy')
%p.settings-message.text-center
......
---
title: Moves domain setting to cluster page
merge_request: 24580
author:
type: added
# frozen_string_literal: true
class MigrateAutoDevOpsDomainToClusterDomain < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
domains_info = connection.exec_query(project_auto_devops_query).rows
domains_info.each_slice(1_000) do |batch|
update_clusters_query = build_clusters_query(Hash[*batch.flatten])
connection.exec_query(update_clusters_query)
end
end
def down
# no-op
end
private
def project_auto_devops_table
@project_auto_devops_table ||= ProjectAutoDevops.arel_table
end
def cluster_projects_table
@cluster_projects_table ||= Clusters::Project.arel_table
end
# Fetches ProjectAutoDevops records with:
# - A domain set
# - With a Clusters::Project related to Project
#
# Returns an array of arrays like:
# => [
# [177, "104.198.38.135.nip.io"],
# [178, "35.232.213.111.nip.io"],
# ...
# ]
# Where the first element is the Cluster ID and
# the second element is the domain.
def project_auto_devops_query
project_auto_devops_table.join(cluster_projects_table, Arel::Nodes::OuterJoin)
.on(project_auto_devops_table[:project_id].eq(cluster_projects_table[:project_id]))
.where(project_auto_devops_table[:domain].not_eq(nil).and(project_auto_devops_table[:domain].not_eq('')))
.project(cluster_projects_table[:cluster_id], project_auto_devops_table[:domain])
.to_sql
end
# Returns an SQL UPDATE query using a CASE statement
# to update multiple cluster rows with different values.
#
# Example:
# UPDATE clusters
# SET domain = (CASE
# WHEN id = 177 then '104.198.38.135.nip.io'
# WHEN id = 178 then '35.232.213.111.nip.io'
# WHEN id = 179 then '35.232.168.149.nip.io'
# WHEN id = 180 then '35.224.116.88.nip.io'
# END)
# WHERE id IN (177,178,179,180);
def build_clusters_query(cluster_domains_info)
<<~HEREDOC
UPDATE clusters
SET domain = (CASE
#{cluster_when_statements(cluster_domains_info)}
END)
WHERE id IN (#{cluster_domains_info.keys.join(",")});
HEREDOC
end
def cluster_when_statements(cluster_domains_info)
cluster_domains_info.map do |cluster_id, domain|
"WHEN id = #{cluster_id} then '#{domain}'"
end.join("\n")
end
end
......@@ -138,9 +138,6 @@ msgstr ""
msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
msgstr ""
msgid "%{nip_domain} can be used as an alternative to a custom domain."
msgstr ""
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
......@@ -1236,7 +1233,7 @@ msgstr ""
msgid "CICD|The Auto DevOps pipeline will run if no alternative CI configuration file is found."
msgstr ""
msgid "CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages."
msgid "CICD|You must add a %{kubernetes_cluster_start}Kubernetes cluster integration%{kubernetes_cluster_end} to this project with a domain in order for your deployment strategy to work correctly."
msgstr ""
msgid "CICD|instance enabled"
......@@ -1509,6 +1506,9 @@ msgstr ""
msgid "Closed (moved)"
msgstr ""
msgid "ClusterIntegration| can be used instead of a custom domain. %{custom_domain_start}More information%{custom_domain_end}"
msgstr ""
msgid "ClusterIntegration| is the default environment scope for this cluster. This means that all jobs, regardless of their environment, will use this cluster. %{environment_scope_start}More information%{environment_scope_end}"
msgstr ""
......@@ -1539,6 +1539,9 @@ msgstr ""
msgid "ClusterIntegration|After installing Ingress, you will need to point your wildcard DNS at the generated external IP address in order to view your app after it is deployed. %{ingressHelpLink}"
msgstr ""
msgid "ClusterIntegration|Alternatively"
msgstr ""
msgid "ClusterIntegration|An error occured while trying to fetch project zones: %{error}"
msgstr ""
......@@ -1560,6 +1563,12 @@ msgstr ""
msgid "ClusterIntegration|Are you sure you want to remove this Kubernetes cluster's integration? This will not delete your actual Kubernetes cluster."
msgstr ""
msgid "ClusterIntegration|Base domain"
msgstr ""
msgid "ClusterIntegration|Before setting a domain, you must first install Ingress on your cluster below."
msgstr ""
msgid "ClusterIntegration|CA Certificate"
msgstr ""
......@@ -1884,6 +1893,9 @@ msgstr ""
msgid "ClusterIntegration|Something went wrong while installing %{title}"
msgstr ""
msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured to the Ingress IP Address below."
msgstr ""
msgid "ClusterIntegration|The IP address is in the process of being assigned. Please check your Kubernetes cluster or Quotas on Google Kubernetes Engine if it takes a long time."
msgstr ""
......
......@@ -13,9 +13,7 @@ class CICD < Page::Base
view 'app/views/projects/settings/ci_cd/_autodevops_form.html.haml' do
element :enable_auto_devops_field, 'check_box :enabled' # rubocop:disable QA/ElementWithPattern
element :domain_field, 'text_field :domain' # rubocop:disable QA/ElementWithPattern
element :enable_auto_devops_button, "%strong= s_('CICD|Default to Auto DevOps pipeline')" # rubocop:disable QA/ElementWithPattern
element :domain_input, "%strong= _('Domain')" # rubocop:disable QA/ElementWithPattern
element :save_changes_button, "submit _('Save changes')" # rubocop:disable QA/ElementWithPattern
end
......@@ -31,10 +29,9 @@ def expand_ci_variables(&block)
end
end
def enable_auto_devops_with_domain(domain)
def enable_auto_devops
expand_section(:autodevops_settings) do
check 'Default to Auto DevOps pipeline'
fill_in 'Domain', with: domain
click_on 'Save changes'
end
end
......
......@@ -6,10 +6,14 @@ module QA
module Resource
class KubernetesCluster < Base
attr_writer :project, :cluster,
:install_helm_tiller, :install_ingress, :install_prometheus, :install_runner
:install_helm_tiller, :install_ingress, :install_prometheus, :install_runner, :domain
attribute :ingress_ip do
Page::Project::Operations::Kubernetes::Show.perform(&:ingress_ip)
ingress_ip_value
end
attribute :domain do
"#{ingress_ip_value}.nip.io"
end
def fabricate!
......@@ -52,6 +56,12 @@ def fabricate!
end
end
end
private
def ingress_ip_value
@ingress_ip_value ||= Page::Project::Operations::Kubernetes::Show.perform(&:ingress_ip)
end
end
end
end
......@@ -52,13 +52,13 @@ def login
end
kubernetes_cluster.populate(:ingress_ip)
@project.visit!
Page::Project::Menu.act { click_ci_cd_settings }
Page::Project::Settings::CICD.perform do |p|
p.enable_auto_devops_with_domain(
"#{kubernetes_cluster.ingress_ip}.nip.io")
p.enable_auto_devops
end
kubernetes_cluster.populate(:domain)
end
after(:all) do
......
......@@ -429,12 +429,14 @@ def go(format: :html)
end
let(:cluster) { create(:cluster, :provided_by_user, cluster_type: :group_type, groups: [group]) }
let(:domain) { 'test-domain.com' }
let(:params) do
{
cluster: {
enabled: false,
name: 'my-new-cluster-name'
name: 'my-new-cluster-name',
domain: domain
}
}
end
......@@ -447,6 +449,20 @@ def go(format: :html)
expect(flash[:notice]).to eq('Kubernetes cluster was successfully updated.')
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
expect(cluster.domain).to eq('test-domain.com')
end
context 'when domain is invalid' do
let(:domain) { 'not-a-valid-domain' }
it 'should not update cluster attributes' do
go
cluster.reload
expect(response).to render_template(:show)
expect(cluster.name).not_to eq('my-new-cluster-name')
expect(cluster.domain).not_to eq('test-domain.com')
end
end
context 'when format is json' do
......@@ -456,7 +472,8 @@ def go(format: :html)
{
cluster: {
enabled: false,
name: 'my-new-cluster-name'
name: 'my-new-cluster-name',
domain: domain
}
}
end
......
# frozen_string_literal: true
require 'spec_helper'
describe 'Clusterable > Show page' do
let(:current_user) { create(:user) }
before do
sign_in(current_user)
end
shared_examples 'editing domain' do
before do
clusterable.add_maintainer(current_user)
end
it 'allow the user to set domain' do
visit cluster_path
within '#cluster-integration' do
fill_in('cluster_domain', with: 'test.com')
click_on 'Save changes'
end
expect(page.status_code).to eq(200)
expect(page).to have_content('Kubernetes cluster was successfully updated.')
end
context 'when there is a cluster with ingress and external ip' do
before do
cluster.create_application_ingress!(external_ip: '192.168.1.100')
visit cluster_path
end
it 'shows help text with the domain as an alternative to custom domain' do
within '#cluster-integration' do
expect(page).to have_content('Alternatively 192.168.1.100.nip.io can be used instead of a custom domain')
end
end
end
context 'when there is no ingress' do
it 'alternative to custom domain is not shown' do
visit cluster_path
within '#cluster-integration' do
expect(page).to have_content('Before setting a domain, you must first install Ingress on your cluster below.')
end
end
end
end
context 'when clusterable is a project' do
it_behaves_like 'editing domain' do
let(:clusterable) { create(:project) }
let(:cluster) { create(:cluster, :provided_by_gcp, :project, projects: [clusterable]) }
let(:cluster_path) { project_cluster_path(clusterable, cluster) }
end
end
context 'when clusterable is a group' do
it_behaves_like 'editing domain' do
let(:clusterable) { create(:group) }
let(:cluster) { create(:cluster, :provided_by_gcp, :group, groups: [clusterable]) }
let(:cluster_path) { group_cluster_path(clusterable, cluster) }
end
end
end
......@@ -98,14 +98,12 @@
expect(page).not_to have_content('instance enabled')
expect(find_field('project_auto_devops_attributes_enabled')).not_to be_checked
check 'Default to Auto DevOps pipeline'
fill_in('project_auto_devops_attributes_domain', with: 'test.com')
click_on 'Save changes'
end
expect(page.status_code).to eq(200)
expect(project.auto_devops).to be_present
expect(project.auto_devops).to be_enabled
expect(project.auto_devops.domain).to eq('test.com')
page.within '#autodevops-settings' do
expect(find_field('project_auto_devops_attributes_enabled')).to be_checked
......@@ -113,29 +111,6 @@
end
end
end
context 'when there is a cluster with ingress and external_ip' do
before do
cluster = create(:cluster, projects: [project])
cluster.create_application_ingress!(external_ip: '192.168.1.100')
end
it 'shows the help text with the nip.io domain as an alternative to custom domain' do
visit project_settings_ci_cd_path(project)
expect(page).to have_content('192.168.1.100.nip.io can be used as an alternative to a custom domain')
end
end
context 'when there is no ingress' do
before do
create(:cluster, projects: [project])
end
it 'alternative to custom domain is not shown' do
visit project_settings_ci_cd_path(project)
expect(page).not_to have_content('can be used as an alternative to a custom domain')
end
end
end
describe 'runners registration token' do
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20190129165720_migrate_auto_dev_ops_domain_to_cluster_domain.rb')
describe MigrateAutoDevOpsDomainToClusterDomain, :migration do
include MigrationHelpers::ClusterHelpers
let(:migration) { described_class.new }
let(:project_auto_devops_table) { table(:project_auto_devops) }
let(:clusters_table) { table(:clusters) }
let(:cluster_projects_table) { table(:cluster_projects) }
# Following lets are needed by MigrationHelpers::ClusterHelpers
let(:cluster_kubernetes_namespaces_table) { table(:clusters_kubernetes_namespaces) }
let(:projects_table) { table(:projects) }
let(:namespaces_table) { table(:namespaces) }
let(:provider_gcp_table) { table(:cluster_providers_gcp) }
let(:platform_kubernetes_table) { table(:cluster_platforms_kubernetes) }
before do
setup_cluster_projects_with_domain(quantity: 20, domain: domain)
end
context 'with ProjectAutoDevOps with no domain' do
let(:domain) { nil }
it 'should not update cluster project' do
migrate!
expect(clusters_without_domain.count).to eq(clusters_table.count)
end
end
context 'with ProjectAutoDevOps with domain' do
let(:domain) { 'example-domain.com' }
it 'should update all cluster projects' do
migrate!
expect(clusters_with_domain.count).to eq(clusters_table.count)
end
end
context 'when only some ProjectAutoDevOps have domain set' do
let(:domain) { 'example-domain.com' }
before do
setup_cluster_projects_with_domain(quantity: 20, domain: nil)
end
it 'should only update specific cluster projects' do
migrate!
project_auto_devops_with_domain.each do |project_auto_devops|
cluster_project = Clusters::Project.find_by(project_id: project_auto_devops.project_id)
cluster = Clusters::Cluster.find(cluster_project.cluster_id)
expect(cluster.domain).to be_present
end
project_auto_devops_without_domain.each do |project_auto_devops|
cluster_project = Clusters::Project.find_by(project_id: project_auto_devops.project_id)
cluster = Clusters::Cluster.find(cluster_project.cluster_id)
expect(cluster.domain).not_to be_present
end
end
end
def setup_cluster_projects_with_domain(quantity:, domain:)
create_cluster_project_list(quantity)