diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-09-23 00:06:29 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-09-23 00:06:29 +0000 |
commit | 98dbb0a488d7b0093f352938210d9578b0f7a8a6 (patch) | |
tree | 25654204f8de2672556a696199fa209b8f8ff1b3 /app | |
parent | 9ce26d3dfdf4194f32c470cd3102b4376a53ef2f (diff) | |
download | gitlab-ce-98dbb0a488d7b0093f352938210d9578b0f7a8a6.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
19 files changed, 166 insertions, 10 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index d386960f3b6..7ea8901ecbb 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -41,6 +41,8 @@ export default class Clusters { managePrometheusPath, clusterEnvironmentsPath, hasRbac, + providerType, + preInstalledKnative, clusterType, clusterStatus, clusterStatusReason, @@ -50,6 +52,7 @@ export default class Clusters { environmentsHelpPath, clustersHelpPath, deployBoardsHelpPath, + cloudRunHelpPath, clusterId, } = document.querySelector('.js-edit-cluster-form').dataset; @@ -65,10 +68,13 @@ export default class Clusters { environmentsHelpPath, clustersHelpPath, deployBoardsHelpPath, + cloudRunHelpPath, ); this.store.setManagePrometheusPath(managePrometheusPath); this.store.updateStatus(clusterStatus); this.store.updateStatusReason(clusterStatusReason); + this.store.updateProviderType(providerType); + this.store.updatePreInstalledKnative(preInstalledKnative); this.store.updateRbac(hasRbac); this.service = new ClustersService({ endpoint: statusPath, @@ -153,6 +159,9 @@ export default class Clusters { ingressHelpPath: this.state.ingressHelpPath, managePrometheusPath: this.state.managePrometheusPath, ingressDnsHelpPath: this.state.ingressDnsHelpPath, + cloudRunHelpPath: this.state.cloudRunHelpPath, + providerType: this.state.providerType, + preInstalledKnative: this.state.preInstalledKnative, rbac: this.state.rbac, }, }); diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue index 64364092016..c6c8dc6352c 100644 --- a/app/assets/javascripts/clusters/components/application_row.vue +++ b/app/assets/javascripts/clusters/components/application_row.vue @@ -78,6 +78,10 @@ export default { required: false, default: false, }, + installedVia: { + type: String, + required: false, + }, version: { type: String, required: false, @@ -311,6 +315,11 @@ export default { > <span v-else class="js-cluster-application-title">{{ title }}</span> </strong> + <span + v-if="installedVia" + class="js-cluster-application-installed-via" + v-html="installedVia" + ></span> <slot name="description"></slot> <div v-if="hasError" class="cluster-application-error text-danger prepend-top-10"> <p class="js-cluster-application-general-error-message append-bottom-0"> diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 27959898fb7..4d3e759d8d4 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -16,7 +16,7 @@ import { s__, sprintf } from '../../locale'; import applicationRow from './application_row.vue'; import clipboardButton from '../../vue_shared/components/clipboard_button.vue'; import KnativeDomainEditor from './knative_domain_editor.vue'; -import { CLUSTER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants'; +import { CLUSTER_TYPE, PROVIDER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; import eventHub from '~/clusters/event_hub'; @@ -54,11 +54,26 @@ export default { required: false, default: '', }, + cloudRunHelpPath: { + type: String, + required: false, + default: '', + }, managePrometheusPath: { type: String, required: false, default: '', }, + providerType: { + type: String, + required: false, + default: '', + }, + preInstalledKnative: { + type: Boolean, + required: false, + default: false, + }, rbac: { type: Boolean, required: false, @@ -156,6 +171,25 @@ export default { knative() { return this.applications.knative; }, + cloudRun() { + return this.providerType === PROVIDER_TYPE.GCP && this.preInstalledKnative; + }, + installedVia() { + if (this.cloudRun) { + return sprintf( + _.escape(s__(`ClusterIntegration|installed via %{installed_via}`)), + { + installed_via: `<a href="${ + this.cloudRunHelpPath + }" target="_blank" rel="noopener noreferrer">${_.escape( + s__('ClusterIntegration|Cloud Run'), + )}</a>`, + }, + false, + ); + } + return null; + }, }, created() { this.helmInstallIllustration = helmInstallIllustration; @@ -468,6 +502,7 @@ export default { :installed="applications.knative.installed" :install-failed="applications.knative.installFailed" :install-application-request-params="{ hostname: applications.knative.hostname }" + :installed-via="installedVia" :uninstallable="applications.knative.uninstallable" :uninstall-successful="applications.knative.uninstallSuccessful" :uninstall-failed="applications.knative.uninstallFailed" @@ -499,7 +534,7 @@ export default { </p> <knative-domain-editor - v-if="knative.installed || (helmInstalled && rbac)" + v-if="(knative.installed || (helmInstalled && rbac)) && !preInstalledKnative" :knative="knative" :ingress-dns-help-path="ingressDnsHelpPath" @save="saveKnativeDomain" diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js index 8fd752092c9..c6e4b7951cf 100644 --- a/app/assets/javascripts/clusters/constants.js +++ b/app/assets/javascripts/clusters/constants.js @@ -5,6 +5,11 @@ export const CLUSTER_TYPE = { PROJECT: 'project_type', }; +// These need to match the available providers in app/models/clusters/providers/ +export const PROVIDER_TYPE = { + GCP: 'gcp', +}; + // These need to match what is returned from the server export const APPLICATION_STATUS = { NO_STATUS: null, @@ -19,6 +24,7 @@ export const APPLICATION_STATUS = { UNINSTALLING: 'uninstalling', UNINSTALL_ERRORED: 'uninstall_errored', ERROR: 'errored', + PRE_INSTALLED: 'pre_installed', }; /* @@ -29,6 +35,7 @@ export const APPLICATION_INSTALLED_STATUSES = [ APPLICATION_STATUS.INSTALLED, APPLICATION_STATUS.UPDATING, APPLICATION_STATUS.UNINSTALLING, + APPLICATION_STATUS.PRE_INSTALLED, ]; // These are only used client-side diff --git a/app/assets/javascripts/clusters/services/application_state_machine.js b/app/assets/javascripts/clusters/services/application_state_machine.js index 6e632519d8a..6bc4be7b93a 100644 --- a/app/assets/javascripts/clusters/services/application_state_machine.js +++ b/app/assets/javascripts/clusters/services/application_state_machine.js @@ -13,6 +13,7 @@ const { UPDATE_ERRORED, UNINSTALLING, UNINSTALL_ERRORED, + PRE_INSTALLED, } = APPLICATION_STATUS; const applicationStateMachine = { @@ -63,6 +64,9 @@ const applicationStateMachine = { uninstallFailed: true, }, }, + [PRE_INSTALLED]: { + target: PRE_INSTALLED, + }, }, }, [NOT_INSTALLABLE]: { @@ -123,6 +127,27 @@ const applicationStateMachine = { }, }, }, + [PRE_INSTALLED]: { + on: { + [UPDATE_EVENT]: { + target: UPDATING, + effects: { + updateFailed: false, + updateSuccessful: false, + }, + }, + [NOT_INSTALLABLE]: { + target: NOT_INSTALLABLE, + }, + [UNINSTALL_EVENT]: { + target: UNINSTALLING, + effects: { + uninstallFailed: false, + uninstallSuccessful: false, + }, + }, + }, + }, [UPDATING]: { on: { [UPDATED]: { diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index 5cddb4cc098..6464461ea0c 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -35,7 +35,10 @@ export default class ClusterStore { environmentsHelpPath: null, clustersHelpPath: null, deployBoardsHelpPath: null, + cloudRunHelpPath: null, status: null, + providerType: null, + preInstalledKnative: false, rbac: false, statusReason: null, applications: { @@ -95,6 +98,7 @@ export default class ClusterStore { environmentsHelpPath, clustersHelpPath, deployBoardsHelpPath, + cloudRunHelpPath, ) { this.state.helpPath = helpPath; this.state.ingressHelpPath = ingressHelpPath; @@ -102,6 +106,7 @@ export default class ClusterStore { this.state.environmentsHelpPath = environmentsHelpPath; this.state.clustersHelpPath = clustersHelpPath; this.state.deployBoardsHelpPath = deployBoardsHelpPath; + this.state.cloudRunHelpPath = cloudRunHelpPath; } setManagePrometheusPath(managePrometheusPath) { @@ -112,6 +117,14 @@ export default class ClusterStore { this.state.status = status; } + updateProviderType(providerType) { + this.state.providerType = providerType; + } + + updatePreInstalledKnative(preInstalledKnative) { + this.state.preInstalledKnative = parseBoolean(preInstalledKnative); + } + updateRbac(rbac) { this.state.rbac = parseBoolean(rbac); } diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index 15f1e8284ff..993aba661f3 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -170,6 +170,7 @@ class Clusters::ClustersController < Clusters::BaseController :zone, :num_nodes, :machine_type, + :cloud_run, :legacy_abac ]).merge( provider_type: :gcp, diff --git a/app/models/clusters/applications/helm.rb b/app/models/clusters/applications/helm.rb index 455cf200fbc..261f6ce8987 100644 --- a/app/models/clusters/applications/helm.rb +++ b/app/models/clusters/applications/helm.rb @@ -27,7 +27,7 @@ module Clusters def set_initial_status return unless not_installable? - self.status = 'installable' if cluster&.platform_kubernetes_active? + self.status = status_states[:installable] if cluster&.platform_kubernetes_active? end # It can only be uninstalled if there are no other applications installed diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb index ec65482a846..ca93bc15be0 100644 --- a/app/models/clusters/applications/jupyter.rb +++ b/app/models/clusters/applications/jupyter.rb @@ -23,7 +23,7 @@ module Clusters return unless cluster&.application_ingress_available? ingress = cluster.application_ingress - self.status = 'installable' if ingress.external_ip_or_hostname? + self.status = status_states[:installable] if ingress.external_ip_or_hostname? end def chart diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index a9b9374622d..f2a3695d2eb 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -21,7 +21,7 @@ module Clusters return unless not_installable? return unless verify_cluster? - self.status = 'installable' + self.status = status_states[:installable] end state_machine :status do @@ -47,6 +47,10 @@ module Clusters { "domain" => hostname }.to_yaml end + def allowed_to_uninstall? + !pre_installed? + end + def install_command Gitlab::Kubernetes::Helm::InstallCommand.new( name: name, diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 231cadfae05..2df30e8ac36 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -194,6 +194,10 @@ module Clusters end end + def knative_pre_installed? + provider&.knative_pre_installed? + end + private def instance_domain diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb index d1b57a21a7d..e748c0a855d 100644 --- a/app/models/clusters/concerns/application_core.rb +++ b/app/models/clusters/concerns/application_core.rb @@ -15,7 +15,7 @@ module Clusters def set_initial_status return unless not_installable? - self.status = 'installable' if cluster&.application_helm_available? + self.status = status_states[:installable] if cluster&.application_helm_available? end def can_uninstall? diff --git a/app/models/clusters/concerns/application_status.rb b/app/models/clusters/concerns/application_status.rb index 342d766f723..b63a596dfee 100644 --- a/app/models/clusters/concerns/application_status.rb +++ b/app/models/clusters/concerns/application_status.rb @@ -28,6 +28,13 @@ module Clusters state :uninstalling, value: 7 state :uninstall_errored, value: 8 + # Used for applications that are pre-installed by the cluster, + # e.g. Knative in GCP Cloud Run enabled clusters + # Because we cannot upgrade or uninstall Knative in these clusters, + # we define only one simple state transition to enter the `pre_installed` state, + # and no exit transitions. + state :pre_installed, value: 9 + event :make_scheduled do transition [:installable, :errored, :installed, :updated, :update_errored, :uninstall_errored] => :scheduled end @@ -41,6 +48,10 @@ module Clusters transition [:updating] => :updated end + event :make_pre_installed do + transition any => :pre_installed + end + event :make_errored do transition any - [:updating, :uninstalling] => :errored transition [:updating] => :update_errored @@ -90,12 +101,18 @@ module Clusters end end + def status_states + self.class.state_machines[:status].states.each_with_object({}) do |state, states| + states[state.name] = state.value + end + end + def updateable? installed? || updated? || update_errored? end def available? - installed? || updated? + pre_installed? || installed? || updated? end def update_in_progress? diff --git a/app/models/clusters/providers/gcp.rb b/app/models/clusters/providers/gcp.rb index 390748bf252..043765f79ac 100644 --- a/app/models/clusters/providers/gcp.rb +++ b/app/models/clusters/providers/gcp.rb @@ -10,6 +10,9 @@ module Clusters default_value_for :zone, 'us-central1-a' default_value_for :num_nodes, 3 default_value_for :machine_type, 'n1-standard-2' + default_value_for :cloud_run, false + + scope :cloud_run, -> { where(cloud_run: true) } attr_encrypted :access_token, mode: :per_attribute_iv, @@ -77,6 +80,10 @@ module Clusters @api_client ||= GoogleApi::CloudPlatform::Client.new(access_token, nil) end + + def knative_pre_installed? + cloud_run? + end end end end diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb index 10eb1141f59..37a74cd1b00 100644 --- a/app/services/boards/issues/list_service.rb +++ b/app/services/boards/issues/list_service.rb @@ -11,9 +11,11 @@ module Boards # rubocop: disable CodeReuse/ActiveRecord def metadata + issues = Issue.arel_table keys = metadata_fields.keys - columns = metadata_fields.values_at(*keys).join(', ') - results = Issue.where(id: fetch_issues.select('issues.id')).pluck(columns) + # TODO: eliminate need for SQL literal fragment + columns = Arel.sql(metadata_fields.values_at(*keys).join(', ')) + results = Issue.where(id: fetch_issues.select(issues[:id])).pluck(columns) Hash[keys.zip(results.flatten)] end diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb index c5cde831964..0aff1bcc8b9 100644 --- a/app/services/clusters/gcp/finalize_creation_service.rb +++ b/app/services/clusters/gcp/finalize_creation_service.rb @@ -11,6 +11,7 @@ module Clusters configure_provider create_gitlab_service_account! configure_kubernetes + configure_pre_installed_knative if provider.knative_pre_installed? cluster.save! rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e log_service_error(e.class.name, provider.id, e.message) @@ -48,6 +49,13 @@ module Clusters token: request_kubernetes_token) end + def configure_pre_installed_knative + knative = cluster.build_application_knative( + hostname: 'example.com' + ) + knative.make_pre_installed! + end + def request_kubernetes_token Clusters::Kubernetes::FetchKubernetesTokenService.new( kube_client, diff --git a/app/services/clusters/gcp/provision_service.rb b/app/services/clusters/gcp/provision_service.rb index 80040511ec2..7dc2d3c32f1 100644 --- a/app/services/clusters/gcp/provision_service.rb +++ b/app/services/clusters/gcp/provision_service.rb @@ -3,6 +3,8 @@ module Clusters module Gcp class ProvisionService + CLOUD_RUN_ADDONS = %i[http_load_balancing istio_config cloud_run_config].freeze + attr_reader :provider def execute(provider) @@ -22,13 +24,16 @@ module Clusters private def get_operation_id + enable_addons = provider.cloud_run? ? CLOUD_RUN_ADDONS : [] + operation = provider.api_client.projects_zones_clusters_create( provider.gcp_project_id, provider.zone, provider.cluster.name, provider.num_nodes, machine_type: provider.machine_type, - legacy_abac: provider.legacy_abac + legacy_abac: provider.legacy_abac, + enable_addons: enable_addons ) unless operation.status == 'PENDING' || operation.status == 'RUNNING' diff --git a/app/views/clusters/clusters/gcp/_form.html.haml b/app/views/clusters/clusters/gcp/_form.html.haml index 4d3e3359ea0..196ad422766 100644 --- a/app/views/clusters/clusters/gcp/_form.html.haml +++ b/app/views/clusters/clusters/gcp/_form.html.haml @@ -65,6 +65,13 @@ %p.form-text.text-muted = s_('ClusterIntegration|Learn more about %{help_link_start_machine_type}machine types%{help_link_end} and %{help_link_start_pricing}pricing%{help_link_end}.').html_safe % { help_link_start_machine_type: help_link_start % { url: machine_type_link_url }, help_link_start_pricing: help_link_start % { url: pricing_link_url }, help_link_end: help_link_end } + .form-group + = provider_gcp_field.check_box :cloud_run, { label: s_('ClusterIntegration|Enable Cloud Run on GKE (beta)'), + label_class: 'label-bold' } + .form-text.text-muted + = s_('ClusterIntegration|Uses the Cloud Run, Istio, and HTTP Load Balancing addons for this cluster.') + = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'cloud-run-on-gke'), target: '_blank' + .form-group = field.check_box :managed, { label: s_('ClusterIntegration|GitLab-managed cluster'), label_class: 'label-bold' } diff --git a/app/views/clusters/clusters/show.html.haml b/app/views/clusters/clusters/show.html.haml index cccba48624b..8b9844bcfc1 100644 --- a/app/views/clusters/clusters/show.html.haml +++ b/app/views/clusters/clusters/show.html.haml @@ -23,12 +23,15 @@ cluster_type: @cluster.cluster_type, cluster_status: @cluster.status_name, cluster_status_reason: @cluster.status_reason, + provider_type: @cluster.provider_type, + pre_installed_knative: @cluster.knative_pre_installed? ? 'true': 'false', help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'), ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-endpoint'), ingress_dns_help_path: help_page_path('user/project/clusters/index.md', anchor: 'manually-determining-the-external-endpoint'), environments_help_path: help_page_path('ci/environments', anchor: 'defining-environments'), clusters_help_path: help_page_path('user/project/clusters/index.md', anchor: 'deploying-to-a-kubernetes-cluster'), deploy_boards_help_path: help_page_path('user/project/deploy_boards.html', anchor: 'enabling-deploy-boards'), + cloud_run_help_path: help_page_path('user/project/clusters/index.md', anchor: 'cloud-run-on-gke'), manage_prometheus_path: manage_prometheus_path, cluster_id: @cluster.id } } |