diff options
author | Grzegorz Bizon <grzegorz@gitlab.com> | 2019-09-06 10:57:52 +0000 |
---|---|---|
committer | Grzegorz Bizon <grzegorz@gitlab.com> | 2019-09-06 10:57:52 +0000 |
commit | 7d3f04b20cfd6b88f02e42987804be1b3999e84d (patch) | |
tree | 9dfff496c3fa5ab2cb5f6a35753b87cb00619804 | |
parent | 7cae5773681819a46f8899e983fbd0c7309001f7 (diff) | |
parent | 01f440e74be51e02c79aff9ac5b6d11a74dcd080 (diff) | |
download | gitlab-ce-7d3f04b20cfd6b88f02e42987804be1b3999e84d.tar.gz |
Merge branch 'instance-group-level-knative' into 'master'
Enable Knative installation on group and instance level clusters
Closes #62667 and #62666
See merge request gitlab-org/gitlab-ce!32128
-rw-r--r-- | app/assets/javascripts/clusters/components/applications.vue | 1 | ||||
-rw-r--r-- | app/models/clusters/cluster.rb | 4 | ||||
-rw-r--r-- | changelogs/unreleased/instance-group-level-knative.yml | 5 | ||||
-rw-r--r-- | doc/user/clusters/applications.md | 3 | ||||
-rw-r--r-- | spec/features/admin/clusters/applications_spec.rb | 21 | ||||
-rw-r--r-- | spec/features/clusters/installing_applications_shared_examples.rb | 228 | ||||
-rw-r--r-- | spec/features/groups/clusters/applications_spec.rb | 23 | ||||
-rw-r--r-- | spec/features/projects/clusters/applications_spec.rb | 229 | ||||
-rw-r--r-- | spec/frontend/clusters/components/applications_spec.js | 4 |
9 files changed, 288 insertions, 230 deletions
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index b6da572b201..27959898fb7 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -458,7 +458,6 @@ export default { </div> </application-row> <application-row - v-if="isProjectCluster" id="knative" :logo-url="knativeLogo" :title="applications.knative.title" diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index ef1af1fc8bc..a976093ac0c 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -10,7 +10,6 @@ module Clusters self.table_name = 'clusters' PROJECT_ONLY_APPLICATIONS = { - Applications::Knative.application_name => Applications::Knative }.freeze APPLICATIONS = { Applications::Helm.application_name => Applications::Helm, @@ -18,7 +17,8 @@ module Clusters Applications::CertManager.application_name => Applications::CertManager, Applications::Prometheus.application_name => Applications::Prometheus, Applications::Runner.application_name => Applications::Runner, - Applications::Jupyter.application_name => Applications::Jupyter + Applications::Jupyter.application_name => Applications::Jupyter, + Applications::Knative.application_name => Applications::Knative }.merge(PROJECT_ONLY_APPLICATIONS).freeze DEFAULT_ENVIRONMENT = '*' KUBE_INGRESS_BASE_DOMAIN = 'KUBE_INGRESS_BASE_DOMAIN' diff --git a/changelogs/unreleased/instance-group-level-knative.yml b/changelogs/unreleased/instance-group-level-knative.yml new file mode 100644 index 00000000000..5108334a3ea --- /dev/null +++ b/changelogs/unreleased/instance-group-level-knative.yml @@ -0,0 +1,5 @@ +--- +title: Allow Knative to be installed on group and instance level clusters +merge_request: 32128 +author: +type: added diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md index 83ddcf61664..f922b8911ae 100644 --- a/doc/user/clusters/applications.md +++ b/doc/user/clusters/applications.md @@ -188,7 +188,8 @@ You can clone repositories from the files tab in Jupyter: ### Knative -> Available for project-level clusters since GitLab 11.5. +> - Available for project-level clusters since GitLab 11.5. +> - Available for group-level and instance-level clusters since GitLab 12.3. [Knative](https://cloud.google.com/knative) provides a platform to create, deploy, and manage serverless workloads from a Kubernetes diff --git a/spec/features/admin/clusters/applications_spec.rb b/spec/features/admin/clusters/applications_spec.rb new file mode 100644 index 00000000000..8310811b43d --- /dev/null +++ b/spec/features/admin/clusters/applications_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_relative '../../../../spec/features/clusters/installing_applications_shared_examples' + +describe 'Instance-level Cluster Applications', :js do + include GoogleApi::CloudPlatformHelpers + + let(:user) { create(:admin) } + + before do + sign_in(user) + end + + describe 'Installing applications' do + include_examples "installing applications on a cluster" do + let(:cluster_path) { admin_cluster_path(cluster) } + let(:cluster_factory_args) { [:instance] } + end + end +end diff --git a/spec/features/clusters/installing_applications_shared_examples.rb b/spec/features/clusters/installing_applications_shared_examples.rb new file mode 100644 index 00000000000..cb8fd8c607c --- /dev/null +++ b/spec/features/clusters/installing_applications_shared_examples.rb @@ -0,0 +1,228 @@ +# frozen_string_literal: true + +shared_examples "installing applications on a cluster" do + before do + visit cluster_path + end + + context 'when cluster is being created' do + let(:cluster) { create(:cluster, :providing_by_gcp, *cluster_factory_args) } + + it 'user is unable to install applications' do + expect(page).not_to have_text('Helm') + expect(page).not_to have_text('Install') + end + end + + context 'when cluster is created' do + let(:cluster) { create(:cluster, :provided_by_gcp, *cluster_factory_args) } + + it 'user can install applications' do + wait_for_requests + + page.within('.js-cluster-application-row-helm') do + expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to be_nil + expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Install') + end + end + + context 'when user installs Helm' do + before do + allow(ClusterInstallAppWorker).to receive(:perform_async) + + page.within('.js-cluster-application-row-helm') do + page.find(:css, '.js-cluster-application-install-button').click + end + + wait_for_requests + end + + it 'shows the status transition' do + page.within('.js-cluster-application-row-helm') do + # FE sends request and gets the response, then the buttons is "Installing" + expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') + + Clusters::Cluster.last.application_helm.make_installing! + + # FE starts polling and update the buttons to "Installing" + expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') + + Clusters::Cluster.last.application_helm.make_installed! + + expect(page).not_to have_css('button', exact_text: 'Install', visible: :all) + expect(page).not_to have_css('button', exact_text: 'Installing', visible: :all) + expect(page).to have_css('.js-cluster-application-uninstall-button:not([disabled])', exact_text: 'Uninstall') + end + + expect(page).to have_content('Helm Tiller was successfully installed on your Kubernetes cluster') + end + end + + context 'when user installs Knative' do + before do + create(:clusters_applications_helm, :installed, cluster: cluster) + end + + context 'on an abac cluster' do + let(:cluster) { create(:cluster, :provided_by_gcp, :rbac_disabled, *cluster_factory_args) } + + it 'shows info block and not be installable' do + page.within('.js-cluster-application-row-knative') do + expect(page).to have_css('.rbac-notice') + expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true') + end + end + end + + context 'on an rbac cluster' do + let(:cluster) { create(:cluster, :provided_by_gcp, *cluster_factory_args) } + + it 'does not show callout block and be installable' do + page.within('.js-cluster-application-row-knative') do + expect(page).not_to have_css('p', text: 'You must have an RBAC-enabled cluster', visible: :all) + expect(page).to have_css('.js-cluster-application-install-button:not([disabled])') + end + end + + describe 'when user clicks install button' do + def domainname_form_value + page.find('.js-knative-domainname').value + end + + before do + allow(ClusterInstallAppWorker).to receive(:perform_async) + allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) + allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) + + page.within('.js-cluster-application-row-knative') do + expect(page).to have_css('.js-cluster-application-install-button:not([disabled])') + + page.find('.js-knative-domainname').set("domain.example.org") + + click_button 'Install' + + wait_for_requests + + expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing') + + Clusters::Cluster.last.application_knative.make_installing! + Clusters::Cluster.last.application_knative.make_installed! + Clusters::Cluster.last.application_knative.update_attribute(:external_ip, '127.0.0.1') + end + end + + it 'shows status transition' do + page.within('.js-cluster-application-row-knative') do + expect(domainname_form_value).to eq('domain.example.org') + expect(page).to have_css('.js-cluster-application-uninstall-button', exact_text: 'Uninstall') + end + + expect(page).to have_content('Knative was successfully installed on your Kubernetes cluster') + expect(page).to have_css('.js-knative-save-domain-button'), exact_text: 'Save changes' + end + + it 'can then update the domain' do + page.within('.js-cluster-application-row-knative') do + expect(ClusterPatchAppWorker).to receive(:perform_async) + + expect(domainname_form_value).to eq('domain.example.org') + + page.find('.js-knative-domainname').set("new.domain.example.org") + + click_button 'Save changes' + + wait_for_requests + + expect(domainname_form_value).to eq('new.domain.example.org') + end + end + end + end + end + + context 'when user installs Cert Manager' do + before do + allow(ClusterInstallAppWorker).to receive(:perform_async) + allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) + allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) + + create(:clusters_applications_helm, :installed, cluster: cluster) + + page.within('.js-cluster-application-row-cert_manager') do + click_button 'Install' + end + end + + it 'shows status transition' do + def email_form_value + page.find('.js-email').value + end + + page.within('.js-cluster-application-row-cert_manager') do + expect(email_form_value).to eq(cluster.user.email) + expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing') + + page.find('.js-email').set("new_email@example.org") + Clusters::Cluster.last.application_cert_manager.make_installing! + + expect(email_form_value).to eq('new_email@example.org') + expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing') + + Clusters::Cluster.last.application_cert_manager.make_installed! + + expect(email_form_value).to eq('new_email@example.org') + expect(page).to have_css('.js-cluster-application-uninstall-button', exact_text: 'Uninstall') + end + + expect(page).to have_content('Cert-Manager was successfully installed on your Kubernetes cluster') + end + end + + context 'when user installs Ingress' do + before do + allow(ClusterInstallAppWorker).to receive(:perform_async) + allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) + allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) + + create(:clusters_applications_helm, :installed, cluster: cluster) + + page.within('.js-cluster-application-row-ingress') do + expect(page).to have_css('.js-cluster-application-install-button:not([disabled])') + page.find(:css, '.js-cluster-application-install-button').click + + wait_for_requests + end + end + + it 'shows the status transition' do + page.within('.js-cluster-application-row-ingress') do + # FE sends request and gets the response, then the buttons is "Installing" + expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') + + Clusters::Cluster.last.application_ingress.make_installing! + + # FE starts polling and update the buttons to "Installing" + expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') + + # The application becomes installed but we keep waiting for external IP address + Clusters::Cluster.last.application_ingress.make_installed! + + expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installed') + expect(page).to have_selector('.js-no-endpoint-message') + expect(page).to have_selector('.js-ingress-ip-loading-icon') + + # We receive the external IP address and display + Clusters::Cluster.last.application_ingress.update!(external_ip: '192.168.1.100') + + expect(page).not_to have_css('button', exact_text: 'Install', visible: :all) + expect(page).not_to have_css('button', exact_text: 'Installing', visible: :all) + expect(page).to have_css('.js-cluster-application-uninstall-button:not([disabled])', exact_text: 'Uninstall') + expect(page).not_to have_css('p', text: 'The endpoint is in the process of being assigned', visible: :all) + expect(page.find('.js-endpoint').value).to eq('192.168.1.100') + end + + expect(page).to have_content('Ingress was successfully installed on your Kubernetes cluster') + end + end + end +end diff --git a/spec/features/groups/clusters/applications_spec.rb b/spec/features/groups/clusters/applications_spec.rb new file mode 100644 index 00000000000..5d48df234eb --- /dev/null +++ b/spec/features/groups/clusters/applications_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_relative '../../../../spec/features/clusters/installing_applications_shared_examples' + +describe 'Group-level Cluster Applications', :js do + include GoogleApi::CloudPlatformHelpers + + let(:group) { create(:group) } + let(:user) { create(:user) } + + before do + group.add_maintainer(user) + sign_in(user) + end + + describe 'Installing applications' do + include_examples "installing applications on a cluster" do + let(:cluster_path) { group_cluster_path(group, cluster) } + let(:cluster_factory_args) { [:group, groups: [group]] } + end + end +end diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb index 3d15095e2da..ce971b158a3 100644 --- a/spec/features/projects/clusters/applications_spec.rb +++ b/spec/features/projects/clusters/applications_spec.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true require 'spec_helper' +require_relative '../../../../spec/features/clusters/installing_applications_shared_examples' -describe 'Clusters Applications', :js do +describe 'Project-level Cluster Applications', :js do include GoogleApi::CloudPlatformHelpers let(:project) { create(:project) } @@ -14,229 +15,9 @@ describe 'Clusters Applications', :js do end describe 'Installing applications' do - before do - visit project_cluster_path(project, cluster) - end - - context 'when cluster is being created' do - let(:cluster) { create(:cluster, :providing_by_gcp, projects: [project]) } - - it 'user is unable to install applications' do - expect(page).not_to have_css('.js-cluster-application-row-helm') - expect(page).not_to have_css('.js-cluster-application-install-button') - end - end - - context 'when cluster is created' do - let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } - - it 'user can install applications' do - wait_for_requests - - page.within('.js-cluster-application-row-helm') do - expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to be_nil - expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Install') - end - end - - context 'when user installs Helm' do - before do - allow(ClusterInstallAppWorker).to receive(:perform_async) - - page.within('.js-cluster-application-row-helm') do - page.find(:css, '.js-cluster-application-install-button').click - end - - wait_for_requests - end - - it 'they see status transition' do - page.within('.js-cluster-application-row-helm') do - # FE sends request and gets the response, then the buttons is "Installing" - expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') - - Clusters::Cluster.last.application_helm.make_installing! - - # FE starts polling and update the buttons to "Installing" - expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') - - Clusters::Cluster.last.application_helm.make_installed! - - expect(page).not_to have_css('.js-cluster-application-install-button') - expect(page).to have_css('.js-cluster-application-uninstall-button:not([disabled])', exact_text: 'Uninstall') - end - - expect(page).to have_content('Helm Tiller was successfully installed on your Kubernetes cluster') - end - end - - context 'when user installs Knative' do - before do - create(:clusters_applications_helm, :installed, cluster: cluster) - end - - context 'on an abac cluster' do - let(:cluster) { create(:cluster, :provided_by_gcp, :rbac_disabled, projects: [project]) } - - it 'shows info block and not be installable' do - page.within('.js-cluster-application-row-knative') do - expect(page).to have_css('.rbac-notice') - expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true') - end - end - end - - context 'on an rbac cluster' do - let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } - - it 'does not show callout block and be installable' do - page.within('.js-cluster-application-row-knative') do - expect(page).not_to have_css('.rbac-notice') - expect(page).to have_css('.js-cluster-application-install-button:not([disabled])') - end - end - - describe 'when user clicks install button' do - def domainname_form_value - page.find('.js-knative-domainname').value - end - - before do - allow(ClusterInstallAppWorker).to receive(:perform_async) - allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) - allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) - - page.within('.js-cluster-application-row-knative') do - expect(page).to have_css('.js-cluster-application-install-button:not([disabled])') - - page.find('.js-knative-domainname').set("domain.example.org") - - click_button 'Install' - - wait_for_requests - - expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing') - - Clusters::Cluster.last.application_knative.make_installing! - Clusters::Cluster.last.application_knative.make_installed! - Clusters::Cluster.last.application_knative.update_attribute(:external_ip, '127.0.0.1') - end - end - - it 'shows status transition' do - page.within('.js-cluster-application-row-knative') do - expect(domainname_form_value).to eq('domain.example.org') - expect(page).to have_css('.js-cluster-application-uninstall-button', exact_text: 'Uninstall') - end - - expect(page).to have_content('Knative was successfully installed on your Kubernetes cluster') - expect(page).to have_css('.js-knative-save-domain-button'), exact_text: 'Save changes' - end - - it 'can then update the domain' do - page.within('.js-cluster-application-row-knative') do - expect(ClusterPatchAppWorker).to receive(:perform_async) - - expect(domainname_form_value).to eq('domain.example.org') - - page.find('.js-knative-domainname').set("new.domain.example.org") - - click_button 'Save changes' - - wait_for_requests - - expect(domainname_form_value).to eq('new.domain.example.org') - end - end - end - end - end - - context 'when user installs Cert Manager' do - before do - allow(ClusterInstallAppWorker).to receive(:perform_async) - allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) - allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) - - create(:clusters_applications_helm, :installed, cluster: cluster) - - page.within('.js-cluster-application-row-cert_manager') do - click_button 'Install' - end - end - - it 'shows status transition' do - def email_form_value - page.find('.js-email').value - end - - page.within('.js-cluster-application-row-cert_manager') do - expect(email_form_value).to eq(cluster.user.email) - expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing') - - page.find('.js-email').set("new_email@example.org") - Clusters::Cluster.last.application_cert_manager.make_installing! - - expect(email_form_value).to eq('new_email@example.org') - expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing') - - Clusters::Cluster.last.application_cert_manager.make_installed! - - expect(email_form_value).to eq('new_email@example.org') - expect(page).to have_css('.js-cluster-application-uninstall-button', exact_text: 'Uninstall') - end - - expect(page).to have_content('Cert-Manager was successfully installed on your Kubernetes cluster') - end - end - - context 'when user installs Ingress' do - context 'when user installs application: Ingress' do - before do - allow(ClusterInstallAppWorker).to receive(:perform_async) - allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) - allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) - - create(:clusters_applications_helm, :installed, cluster: cluster) - - page.within('.js-cluster-application-row-ingress') do - expect(page).to have_css('.js-cluster-application-install-button:not([disabled])') - page.find(:css, '.js-cluster-application-install-button').click - - wait_for_requests - end - end - - it 'they see status transition' do - page.within('.js-cluster-application-row-ingress') do - # FE sends request and gets the response, then the buttons is "Installing" - expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') - - Clusters::Cluster.last.application_ingress.make_installing! - - # FE starts polling and update the buttons to "Installing" - expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') - - # The application becomes installed but we keep waiting for external IP address - Clusters::Cluster.last.application_ingress.make_installed! - - expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installed') - expect(page).to have_selector('.js-no-endpoint-message') - expect(page).to have_selector('.js-ingress-ip-loading-icon') - - # We receive the external IP address and display - Clusters::Cluster.last.application_ingress.update!(external_ip: '192.168.1.100') - - expect(page).not_to have_css('.js-cluster-application-install-button') - expect(page).to have_css('.js-cluster-application-uninstall-button:not([disabled])', exact_text: 'Uninstall') - expect(page).not_to have_selector('.js-no-endpoint-message') - expect(page.find('.js-endpoint').value).to eq('192.168.1.100') - end - - expect(page).to have_content('Ingress was successfully installed on your Kubernetes cluster') - end - end - end + include_examples "installing applications on a cluster" do + let(:cluster_path) { project_cluster_path(project, cluster) } + let(:cluster_factory_args) { [projects: [project]] } end end end diff --git a/spec/frontend/clusters/components/applications_spec.js b/spec/frontend/clusters/components/applications_spec.js index 1d8984cea0a..fbcab078993 100644 --- a/spec/frontend/clusters/components/applications_spec.js +++ b/spec/frontend/clusters/components/applications_spec.js @@ -89,7 +89,7 @@ describe('Applications', () => { }); it('renders a row for Knative', () => { - expect(vm.$el.querySelector('.js-cluster-application-row-knative')).toBeNull(); + expect(vm.$el.querySelector('.js-cluster-application-row-knative')).not.toBeNull(); }); }); @@ -126,7 +126,7 @@ describe('Applications', () => { }); it('renders a row for Knative', () => { - expect(vm.$el.querySelector('.js-cluster-application-row-knative')).toBeNull(); + expect(vm.$el.querySelector('.js-cluster-application-row-knative')).not.toBeNull(); }); }); |