diff options
19 files changed, 421 insertions, 62 deletions
diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index b9717b97640..483842fe456 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -127,6 +127,7 @@ class Clusters::ClustersController < Clusters::BaseController params.require(:cluster).permit( :enabled, :environment_scope, + :domain, platform_kubernetes_attributes: [ :namespace ] @@ -136,6 +137,7 @@ class Clusters::ClustersController < Clusters::BaseController :enabled, :name, :environment_scope, + :domain, platform_kubernetes_attributes: [ :api_url, :token, diff --git a/app/helpers/auto_devops_helper.rb b/app/helpers/auto_devops_helper.rb index 516c8a353ea..8628c90dc51 100644 --- a/app/helpers/auto_devops_helper.rb +++ b/app/helpers/auto_devops_helper.rb @@ -26,17 +26,6 @@ module AutoDevopsHelper 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) diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index a2c48973fa5..2b677961df5 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -49,7 +49,7 @@ module Clusters 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 @@ module Clusters 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 @@ module Clusters 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") diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 8f3424db295..c8969351ed9 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -98,6 +98,8 @@ module Clusters .append(key: 'KUBE_NAMESPACE', value: actual_namespace) .append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) end + + variables.concat(cluster.predefined_variables) end end diff --git a/app/models/project_auto_devops.rb b/app/models/project_auto_devops.rb index 2253ad7b543..d254ec158ca 100644 --- a/app/models/project_auto_devops.rb +++ b/app/models/project_auto_devops.rb @@ -24,6 +24,9 @@ class ProjectAutoDevops < ActiveRecord::Base 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? diff --git a/app/views/clusters/clusters/_form.html.haml b/app/views/clusters/clusters/_form.html.haml index 4c47e11927e..068f14364ec 100644 --- a/app/views/clusters/clusters/_form.html.haml +++ b/app/views/clusters/clusters/_form.html.haml @@ -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' diff --git a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml index 5ec5a06396e..c2bbcf8fcaf 100644 --- a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml +++ b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml @@ -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 diff --git a/changelogs/unreleased/52363-ui-changes-to-cluster-and-ado-pages.yml b/changelogs/unreleased/52363-ui-changes-to-cluster-and-ado-pages.yml new file mode 100644 index 00000000000..25f01f95177 --- /dev/null +++ b/changelogs/unreleased/52363-ui-changes-to-cluster-and-ado-pages.yml @@ -0,0 +1,5 @@ +--- +title: Moves domain setting to cluster page +merge_request: 24580 +author: +type: added diff --git a/db/migrate/20190129165720_migrate_auto_dev_ops_domain_to_cluster_domain.rb b/db/migrate/20190129165720_migrate_auto_dev_ops_domain_to_cluster_domain.rb new file mode 100644 index 00000000000..2d3e9acaa62 --- /dev/null +++ b/db/migrate/20190129165720_migrate_auto_dev_ops_domain_to_cluster_domain.rb @@ -0,0 +1,78 @@ +# 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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ccdbc63c51e..8600e6fa394 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/qa/qa/page/project/settings/ci_cd.rb b/qa/qa/page/project/settings/ci_cd.rb index 12c2409a5a7..2de39b8ebf5 100644 --- a/qa/qa/page/project/settings/ci_cd.rb +++ b/qa/qa/page/project/settings/ci_cd.rb @@ -13,9 +13,7 @@ module QA # rubocop:disable Naming/FileName 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 @@ module QA # rubocop:disable Naming/FileName 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 diff --git a/qa/qa/resource/kubernetes_cluster.rb b/qa/qa/resource/kubernetes_cluster.rb index d67e5f6da20..19c6dc8890d 100644 --- a/qa/qa/resource/kubernetes_cluster.rb +++ b/qa/qa/resource/kubernetes_cluster.rb @@ -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 @@ module QA end end end + + private + + def ingress_ip_value + @ingress_ip_value ||= Page::Project::Operations::Kubernetes::Show.perform(&:ingress_ip) + end end end end diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb index b0ff83db86b..5c8ec465143 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb @@ -52,13 +52,13 @@ module QA 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 diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb index 0f28499194e..d5a149a57df 100644 --- a/spec/controllers/groups/clusters_controller_spec.rb +++ b/spec/controllers/groups/clusters_controller_spec.rb @@ -429,12 +429,14 @@ describe Groups::ClustersController do 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 @@ describe Groups::ClustersController do 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 @@ describe Groups::ClustersController do { cluster: { enabled: false, - name: 'my-new-cluster-name' + name: 'my-new-cluster-name', + domain: domain } } end diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb new file mode 100644 index 00000000000..844008f841a --- /dev/null +++ b/spec/features/clusters/cluster_detail_page_spec.rb @@ -0,0 +1,69 @@ +# 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 diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb index 6f8ec0015ad..4c85abe9971 100644 --- a/spec/features/projects/settings/pipelines_settings_spec.rb +++ b/spec/features/projects/settings/pipelines_settings_spec.rb @@ -98,14 +98,12 @@ describe "Projects > Settings > Pipelines settings" do 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 @@ describe "Projects > Settings > Pipelines settings" do 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 diff --git a/spec/migrations/migrate_auto_dev_ops_domain_to_cluster_domain_spec.rb b/spec/migrations/migrate_auto_dev_ops_domain_to_cluster_domain_spec.rb new file mode 100644 index 00000000000..09013ee4bd0 --- /dev/null +++ b/spec/migrations/migrate_auto_dev_ops_domain_to_cluster_domain_spec.rb @@ -0,0 +1,100 @@ +# 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) + + cluster_projects = cluster_projects_table.last(quantity) + + cluster_projects.each do |cluster_project| + project_auto_devops_table.create( + project_id: cluster_project.project_id, + enabled: true, + domain: domain + ) + end + end + + def project_auto_devops_with_domain + project_auto_devops_table.where.not("domain IS NULL OR domain = ''") + end + + def project_auto_devops_without_domain + project_auto_devops_table.where("domain IS NULL OR domain = ''") + end + + def clusters_with_domain + clusters_table.where.not("domain IS NULL OR domain = ''") + end + + def clusters_without_domain + clusters_table.where("domain IS NULL OR domain = ''") + end +end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 0161db740ee..abef586d258 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -30,6 +30,7 @@ describe Clusters::Cluster do it { is_expected.to delegate_method(:available?).to(:application_ingress).with_prefix } it { is_expected.to delegate_method(:available?).to(:application_prometheus).with_prefix } it { is_expected.to delegate_method(:available?).to(:application_knative).with_prefix } + it { is_expected.to delegate_method(:external_ip).to(:application_ingress).with_prefix } it { is_expected.to respond_to :project } @@ -514,4 +515,62 @@ describe Clusters::Cluster do it { is_expected.to be_falsey } end end + + describe '#has_domain?' do + subject { cluster.has_domain? } + + context 'with domain set at instance level' do + let(:cluster) { create(:cluster, :provided_by_gcp) } + + before do + stub_application_setting(auto_devops_domain: 'global_domain.com') + end + + it { is_expected.to be_truthy } + end + + context 'with domain set in cluster' do + let(:cluster) { create(:cluster, :provided_by_gcp, :with_domain) } + + it { is_expected.to be_truthy } + end + + context 'when domain is not set at instance level nor in cluster' do + let(:cluster) { create(:cluster, :provided_by_gcp) } + + it { is_expected.to be_falsy } + end + end + + describe '#predefined_variables' do + subject { cluster.predefined_variables } + + context 'with an instance domain' do + let(:cluster) { create(:cluster, :provided_by_gcp) } + + before do + stub_application_setting(auto_devops_domain: 'global_domain.com') + end + + it 'should include KUBE_INGRESS_BASE_DOMAIN' do + expect(subject.to_hash).to include(KUBE_INGRESS_BASE_DOMAIN: 'global_domain.com') + end + end + + context 'with a cluster domain' do + let(:cluster) { create(:cluster, :provided_by_gcp, domain: 'example.com') } + + it 'should include KUBE_INGRESS_BASE_DOMAIN' do + expect(subject.to_hash).to include(KUBE_INGRESS_BASE_DOMAIN: 'example.com') + end + end + + context 'with no domain' do + let(:cluster) { create(:cluster) } + + it 'should return an empty array' do + expect(subject.to_hash).to be_empty + end + end + end end diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb index 6c8a223092e..c273fa7e164 100644 --- a/spec/models/clusters/platforms/kubernetes_spec.rb +++ b/spec/models/clusters/platforms/kubernetes_spec.rb @@ -297,6 +297,19 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching end end end + + context 'with a domain' do + let!(:cluster) do + create(:cluster, :provided_by_gcp, :with_domain, + platform_kubernetes: kubernetes) + end + + it 'sets KUBE_INGRESS_BASE_DOMAIN' do + expect(subject).to include( + { key: 'KUBE_INGRESS_BASE_DOMAIN', value: cluster.domain, public: true } + ) + end + end end describe '#terminals' do |