diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-18 03:06:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-18 03:06:28 +0000 |
commit | c1f270b8ba4602952c36ce042e5eae439b22f9a6 (patch) | |
tree | 205917e3dc8dcaeaaa0de55e2618eaca4197c4c2 | |
parent | 7f4a1ba886819078d1fa0bfc348e3743f0e2b2f2 (diff) | |
download | gitlab-ce-c1f270b8ba4602952c36ce042e5eae439b22f9a6.tar.gz |
Add latest changes from gitlab-org/gitlab@master
73 files changed, 953 insertions, 84 deletions
diff --git a/app/assets/images/cluster_app_logos/crossplane.png b/app/assets/images/cluster_app_logos/crossplane.png Binary files differnew file mode 100644 index 00000000000..32d8175108c --- /dev/null +++ b/app/assets/images/cluster_app_logos/crossplane.png diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index d471dcb1b06..75909dd9d20 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -8,7 +8,7 @@ import Flash from '../flash'; import Poll from '../lib/utils/poll'; import initSettingsPanels from '../settings_panels'; import eventHub from './event_hub'; -import { APPLICATION_STATUS, INGRESS, INGRESS_DOMAIN_SUFFIX } from './constants'; +import { APPLICATION_STATUS, INGRESS, INGRESS_DOMAIN_SUFFIX, CROSSPLANE } from './constants'; import ClustersService from './services/clusters_service'; import ClustersStore from './stores/clusters_store'; import Applications from './components/applications.vue'; @@ -39,6 +39,7 @@ export default class Clusters { installKnativePath, updateKnativePath, installElasticStackPath, + installCrossplanePath, installPrometheusPath, managePrometheusPath, clusterEnvironmentsPath, @@ -83,6 +84,7 @@ export default class Clusters { installHelmEndpoint: installHelmPath, installIngressEndpoint: installIngressPath, installCertManagerEndpoint: installCertManagerPath, + installCrossplaneEndpoint: installCrossplanePath, installRunnerEndpoint: installRunnerPath, installPrometheusEndpoint: installPrometheusPath, installJupyterEndpoint: installJupyterPath, @@ -227,6 +229,7 @@ export default class Clusters { eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data)); eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data)); eventHub.$on('uninstallApplication', data => this.uninstallApplication(data)); + eventHub.$on('setCrossplaneProviderStack', data => this.setCrossplaneProviderStack(data)); // Add event listener to all the banner close buttons this.addBannerCloseHandler(this.unreachableContainer, 'unreachable'); this.addBannerCloseHandler(this.authenticationFailureContainer, 'authentication_failure'); @@ -238,6 +241,7 @@ export default class Clusters { eventHub.$off('updateApplication', this.updateApplication); eventHub.$off('saveKnativeDomain'); eventHub.$off('setKnativeHostname'); + eventHub.$off('setCrossplaneProviderStack'); eventHub.$off('uninstallApplication'); } @@ -404,18 +408,33 @@ export default class Clusters { } installApplication({ id: appId, params }) { - this.store.updateAppProperty(appId, 'requestReason', null); - this.store.updateAppProperty(appId, 'statusReason', null); + return Clusters.validateInstallation(appId, params) + .then(() => { + this.store.updateAppProperty(appId, 'requestReason', null); + this.store.updateAppProperty(appId, 'statusReason', null); + this.store.installApplication(appId); + + // eslint-disable-next-line promise/no-nesting + this.service.installApplication(appId, params).catch(() => { + this.store.notifyInstallFailure(appId); + this.store.updateAppProperty( + appId, + 'requestReason', + s__('ClusterIntegration|Request to begin installing failed'), + ); + }); + }) + .catch(error => this.store.updateAppProperty(appId, 'validationError', error)); + } - this.store.installApplication(appId); + static validateInstallation(appId, params) { + return new Promise((resolve, reject) => { + if (appId === CROSSPLANE && !params.stack) { + reject(s__('ClusterIntegration|Select a stack to install Crossplane.')); + return; + } - return this.service.installApplication(appId, params).catch(() => { - this.store.notifyInstallFailure(appId); - this.store.updateAppProperty( - appId, - 'requestReason', - s__('ClusterIntegration|Request to begin installing failed'), - ); + resolve(); }); } @@ -463,6 +482,12 @@ export default class Clusters { this.store.updateAppProperty(appId, 'hostname', data.hostname); } + setCrossplaneProviderStack(data) { + const appId = data.id; + this.store.updateAppProperty(appId, 'stack', data.stack.code); + this.store.updateAppProperty(appId, 'validationError', null); + } + destroy() { this.destroyed = true; diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 44d77277cc5..a951a6bfeea 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -9,6 +9,7 @@ import jeagerLogo from 'images/cluster_app_logos/jeager.png'; import jupyterhubLogo from 'images/cluster_app_logos/jupyterhub.png'; import kubernetesLogo from 'images/cluster_app_logos/kubernetes.png'; import certManagerLogo from 'images/cluster_app_logos/cert_manager.png'; +import crossplaneLogo from 'images/cluster_app_logos/crossplane.png'; import knativeLogo from 'images/cluster_app_logos/knative.png'; import meltanoLogo from 'images/cluster_app_logos/meltano.png'; import prometheusLogo from 'images/cluster_app_logos/prometheus.png'; @@ -20,6 +21,7 @@ import KnativeDomainEditor from './knative_domain_editor.vue'; 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'; +import CrossplaneProviderStack from './crossplane_provider_stack.vue'; export default { components: { @@ -28,6 +30,7 @@ export default { LoadingButton, GlLoadingIcon, KnativeDomainEditor, + CrossplaneProviderStack, }, props: { type: { @@ -89,6 +92,7 @@ export default { jupyterhubLogo, kubernetesLogo, certManagerLogo, + crossplaneLogo, knativeLogo, meltanoLogo, prometheusLogo, @@ -116,6 +120,12 @@ export default { certManagerInstalled() { return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED; }, + crossplaneInstalled() { + return this.applications.crossplane.status === APPLICATION_STATUS.INSTALLED; + }, + enableClusterApplicationCrossplane() { + return gon.features && gon.features.enableClusterApplicationCrossplane; + }, enableClusterApplicationElasticStack() { return gon.features && gon.features.enableClusterApplicationElasticStack; }, @@ -151,6 +161,24 @@ export default { false, ); }, + crossplaneDescription() { + return sprintf( + _.escape( + s__( + `ClusterIntegration|Crossplane enables declarative provisioning of managed services from your cloud of choice using %{kubectl} or %{gitlabIntegrationLink}. +Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on.`, + ), + ), + { + gitlabIntegrationLink: `<a href="https://docs.gitlab.com/ce/user/project/integrations/crossplane.html" + target="_blank" rel="noopener noreferrer"> + ${_.escape(s__('ClusterIntegration|Gitlab Integration'))}</a>`, + kubectl: `<code>kubectl</code>`, + }, + false, + ); + }, + prometheusDescription() { return sprintf( _.escape( @@ -182,6 +210,9 @@ export default { knative() { return this.applications.knative; }, + crossplane() { + return this.applications.crossplane; + }, cloudRun() { return this.providerType === PROVIDER_TYPE.GCP && this.preInstalledKnative; }, @@ -218,6 +249,12 @@ export default { hostname, }); }, + setCrossplaneProviderStack(stack) { + eventHub.$emit('setCrossplaneProviderStack', { + id: 'crossplane', + stack, + }); + }, }, }; </script> @@ -228,7 +265,7 @@ export default { <p class="append-bottom-0"> {{ s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster. - Helm Tiller is required to install any of the following applications.`) + Helm Tiller is required to install any of the following applications.`) }} <a :href="helpPath">{{ __('More information') }}</a> </p> @@ -253,9 +290,9 @@ export default { <div slot="description"> {{ s__(`ClusterIntegration|Helm streamlines installing - and managing Kubernetes applications. - Tiller runs inside of your Kubernetes Cluster, - and manages releases of your charts.`) + and managing Kubernetes applications. + Tiller runs inside of your Kubernetes Cluster, + and manages releases of your charts.`) }} </div> </application-row> @@ -263,7 +300,7 @@ export default { <div class="svg-container" v-html="helmInstallIllustration"></div> {{ s__(`ClusterIntegration|You must first install Helm Tiller before - installing the applications below`) + installing the applications below`) }} </div> <application-row @@ -286,8 +323,8 @@ export default { <p> {{ s__(`ClusterIntegration|Ingress gives you a way to route - requests to services based on the request host or path, - centralizing a number of services into a single entrypoint.`) + requests to services based on the request host or path, + centralizing a number of services into a single entrypoint.`) }} </p> @@ -319,8 +356,8 @@ export default { <p class="form-text text-muted"> {{ s__(`ClusterIntegration|Point a wildcard DNS to this - generated endpoint in order to access - your application after it has been deployed.`) + generated endpoint in order to access + your application after it has been deployed.`) }} <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> {{ __('More information') }} @@ -331,8 +368,8 @@ export default { <p v-if="!ingressExternalEndpoint" class="settings-message js-no-endpoint-message"> {{ s__(`ClusterIntegration|The endpoint is in - the process of being assigned. Please check your Kubernetes - cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) + the process of being assigned. Please check your Kubernetes + cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) }} <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> {{ __('More information') }} @@ -379,7 +416,7 @@ export default { <p class="form-text text-muted"> {{ s__(`ClusterIntegration|Issuers represent a certificate authority. - You must provide an email address for your Issuer. `) + You must provide an email address for your Issuer. `) }} <a href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email" @@ -435,13 +472,41 @@ export default { <div slot="description"> {{ s__(`ClusterIntegration|GitLab Runner connects to the - repository and executes CI/CD jobs, - pushing results back and deploying - applications to production.`) + repository and executes CI/CD jobs, + pushing results back and deploying + applications to production.`) }} </div> </application-row> <application-row + v-if="enableClusterApplicationCrossplane" + id="crossplane" + :logo-url="crossplaneLogo" + :title="applications.crossplane.title" + :status="applications.crossplane.status" + :status-reason="applications.crossplane.statusReason" + :request-status="applications.crossplane.requestStatus" + :request-reason="applications.crossplane.requestReason" + :installed="applications.crossplane.installed" + :install-failed="applications.crossplane.installFailed" + :uninstallable="applications.crossplane.uninstallable" + :uninstall-successful="applications.crossplane.uninstallSuccessful" + :uninstall-failed="applications.crossplane.uninstallFailed" + :install-application-request-params="{ stack: applications.crossplane.stack }" + :disabled="!helmInstalled" + title-link="https://crossplane.io" + > + <template> + <div slot="description"> + <p v-html="crossplaneDescription"></p> + <div class="form-group"> + <CrossplaneProviderStack :crossplane="crossplane" @set="setCrossplaneProviderStack" /> + </div> + </div> + </template> + </application-row> + + <application-row id="jupyter" :logo-url="jupyterhubLogo" :title="applications.jupyter.title" @@ -462,10 +527,10 @@ export default { <p> {{ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns, - manages, and proxies multiple instances of the single-user - Jupyter notebook server. JupyterHub can be used to serve - notebooks to a class of students, a corporate data science group, - or a scientific research group.`) + manages, and proxies multiple instances of the single-user + Jupyter notebook server. JupyterHub can be used to serve + notebooks to a class of students, a corporate data science group, + or a scientific research group.`) }} </p> @@ -492,7 +557,7 @@ export default { <p v-if="ingressInstalled" class="form-text text-muted"> {{ s__(`ClusterIntegration|Replace this with your own hostname if you want. - If you do so, point hostname to Ingress IP Address from above.`) + If you do so, point hostname to Ingress IP Address from above.`) }} <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> {{ __('More information') }} @@ -538,9 +603,9 @@ export default { <p> {{ s__(`ClusterIntegration|Knative extends Kubernetes to provide - a set of middleware components that are essential to build modern, - source-centric, and container-based applications that can run - anywhere: on premises, in the cloud, or even in a third-party data center.`) + a set of middleware components that are essential to build modern, + source-centric, and container-based applications that can run + anywhere: on premises, in the cloud, or even in a third-party data center.`) }} </p> @@ -612,7 +677,7 @@ export default { <p v-if="ingressInstalled" class="form-text text-muted"> {{ s__(`ClusterIntegration|Replace this with your own hostname if you want. - If you do so, point hostname to Ingress IP Address from above.`) + If you do so, point hostname to Ingress IP Address from above.`) }} <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> {{ __('More information') }} diff --git a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue new file mode 100644 index 00000000000..966918ae636 --- /dev/null +++ b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue @@ -0,0 +1,93 @@ +<script> +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import Icon from '~/vue_shared/components/icon.vue'; +import { s__ } from '../../locale'; + +export default { + name: 'CrossplaneProviderStack', + components: { + GlDropdown, + GlDropdownItem, + Icon, + }, + props: { + stacks: { + type: Array, + required: false, + default: () => [ + { + name: s__('Google Cloud Platform'), + code: 'gcp', + }, + { + name: s__('Amazon Web Services'), + code: 'aws', + }, + { + name: s__('Microsoft Azure'), + code: 'azure', + }, + { + name: s__('Rook'), + code: 'rook', + }, + ], + }, + crossplane: { + type: Object, + required: true, + }, + }, + computed: { + dropdownText() { + const result = this.stacks.reduce((map, obj) => { + // eslint-disable-next-line no-param-reassign + map[obj.code] = obj.name; + return map; + }, {}); + const { stack } = this.crossplane; + if (stack !== '') { + return result[stack]; + } + return s__('Select Stack'); + }, + validationError() { + return this.crossplane.validationError; + }, + }, + methods: { + selectStack(stack) { + this.$emit('set', stack); + }, + }, +}; +</script> + +<template> + <div> + <label> + {{ s__('ClusterIntegration|Enabled stack') }} + </label> + <gl-dropdown + :disabled="crossplane.installed" + :text="dropdownText" + toggle-class="dropdown-menu-toggle gl-field-error-outline" + class="w-100" + :class="{ 'gl-show-field-errors': validationError }" + > + <gl-dropdown-item v-for="stack in stacks" :key="stack.code" @click="selectStack(stack)"> + <span class="ml-1">{{ stack.name }}</span> + </gl-dropdown-item> + </gl-dropdown> + <span v-if="validationError" class="gl-field-error">{{ validationError }}</span> + <p class="form-text text-muted"> + {{ s__(`You must select a stack for configuring your cloud provider. Learn more about`) }} + <a + href="https://crossplane.io/docs/master/stacks-guide.html" + target="_blank" + rel="noopener noreferrer" + >{{ __('Crossplane') }}</a + > + </p> + </div> +</template> diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js index d7152e32376..9f98f170fb0 100644 --- a/app/assets/javascripts/clusters/constants.js +++ b/app/assets/javascripts/clusters/constants.js @@ -50,6 +50,7 @@ export const JUPYTER = 'jupyter'; export const KNATIVE = 'knative'; export const RUNNER = 'runner'; export const CERT_MANAGER = 'cert_manager'; +export const CROSSPLANE = 'crossplane'; export const PROMETHEUS = 'prometheus'; export const ELASTIC_STACK = 'elastic_stack'; diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js index dab4da04bf3..333fb293a15 100644 --- a/app/assets/javascripts/clusters/services/clusters_service.js +++ b/app/assets/javascripts/clusters/services/clusters_service.js @@ -7,6 +7,7 @@ export default class ClusterService { helm: this.options.installHelmEndpoint, ingress: this.options.installIngressEndpoint, cert_manager: this.options.installCertManagerEndpoint, + crossplane: this.options.installCrossplaneEndpoint, runner: this.options.installRunnerEndpoint, prometheus: this.options.installPrometheusEndpoint, jupyter: this.options.installJupyterEndpoint, diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index 6304e81c296..35dbf951551 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -6,6 +6,7 @@ import { KNATIVE, CERT_MANAGER, ELASTIC_STACK, + CROSSPLANE, RUNNER, APPLICATION_INSTALLED_STATUSES, APPLICATION_STATUS, @@ -26,6 +27,7 @@ const applicationInitialState = { uninstallable: false, uninstallFailed: false, uninstallSuccessful: false, + validationError: null, }; export default class ClusterStore { @@ -58,6 +60,11 @@ export default class ClusterStore { title: s__('ClusterIntegration|Cert-Manager'), email: null, }, + crossplane: { + ...applicationInitialState, + title: s__('ClusterIntegration|Crossplane'), + stack: null, + }, runner: { ...applicationInitialState, title: s__('ClusterIntegration|GitLab Runner'), @@ -203,6 +210,9 @@ export default class ClusterStore { } else if (appId === CERT_MANAGER) { this.state.applications.cert_manager.email = this.state.applications.cert_manager.email || serverAppEntry.email; + } else if (appId === CROSSPLANE) { + this.state.applications.crossplane.stack = + this.state.applications.crossplane.stack || serverAppEntry.stack; } else if (appId === JUPYTER) { this.state.applications.jupyter.hostname = this.updateHostnameIfUnset( this.state.applications.jupyter.hostname, diff --git a/app/controllers/clusters/applications_controller.rb b/app/controllers/clusters/applications_controller.rb index 5364116a5f8..be68d0d0a1d 100644 --- a/app/controllers/clusters/applications_controller.rb +++ b/app/controllers/clusters/applications_controller.rb @@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController end def cluster_application_params - params.permit(:application, :hostname, :kibana_hostname, :email) + params.permit(:application, :hostname, :kibana_hostname, :email, :stack) end def cluster_application_destroy_params diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index 5d6ce4f342c..9a539cf7c24 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -17,6 +17,7 @@ class Clusters::ClustersController < Clusters::BaseController end before_action only: [:show] do push_frontend_feature_flag(:enable_cluster_application_elastic_stack) + push_frontend_feature_flag(:enable_cluster_application_crossplane) end helper_method :token_in_session diff --git a/app/models/clusters/applications/crossplane.rb b/app/models/clusters/applications/crossplane.rb new file mode 100644 index 00000000000..36246b26066 --- /dev/null +++ b/app/models/clusters/applications/crossplane.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Clusters + module Applications + class Crossplane < ApplicationRecord + VERSION = '0.4.1' + + self.table_name = 'clusters_applications_crossplane' + + include ::Clusters::Concerns::ApplicationCore + include ::Clusters::Concerns::ApplicationStatus + include ::Clusters::Concerns::ApplicationVersion + include ::Clusters::Concerns::ApplicationData + + default_value_for :version, VERSION + + default_value_for :stack do |crossplane| + '' + end + + validates :stack, presence: true + + def chart + 'crossplane/crossplane' + end + + def repository + 'https://charts.crossplane.io/alpha' + end + + def install_command + Gitlab::Kubernetes::Helm::InstallCommand.new( + name: 'crossplane', + repository: repository, + version: VERSION, + rbac: cluster.platform_kubernetes_rbac?, + chart: chart, + files: files + ) + end + + def values + crossplane_values.to_yaml + end + + private + + def crossplane_values + { + "clusterStacks" => { + self.stack => { + "deploy" => true, + "version" => "alpha" + } + } + } + end + end + end +end diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index ac2b63b194f..f522f3f2fdb 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -14,6 +14,7 @@ module Clusters Applications::Helm.application_name => Applications::Helm, Applications::Ingress.application_name => Applications::Ingress, Applications::CertManager.application_name => Applications::CertManager, + Applications::Crossplane.application_name => Applications::Crossplane, Applications::Prometheus.application_name => Applications::Prometheus, Applications::Runner.application_name => Applications::Runner, Applications::Jupyter.application_name => Applications::Jupyter, @@ -47,6 +48,7 @@ module Clusters has_one_cluster_application :helm has_one_cluster_application :ingress has_one_cluster_application :cert_manager + has_one_cluster_application :crossplane has_one_cluster_application :prometheus has_one_cluster_application :runner has_one_cluster_application :jupyter diff --git a/app/serializers/cluster_application_entity.rb b/app/serializers/cluster_application_entity.rb index a5b983d4074..218bdd21e37 100644 --- a/app/serializers/cluster_application_entity.rb +++ b/app/serializers/cluster_application_entity.rb @@ -10,6 +10,7 @@ class ClusterApplicationEntity < Grape::Entity expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) } expose :kibana_hostname, if: -> (e, _) { e.respond_to?(:kibana_hostname) } expose :email, if: -> (e, _) { e.respond_to?(:email) } + expose :stack, if: -> (e, _) { e.respond_to?(:stack) } expose :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) } expose :can_uninstall?, as: :can_uninstall end diff --git a/app/services/clusters/applications/base_service.rb b/app/services/clusters/applications/base_service.rb index 1a6f6e3aa6f..c9f7917938f 100644 --- a/app/services/clusters/applications/base_service.rb +++ b/app/services/clusters/applications/base_service.rb @@ -27,6 +27,10 @@ module Clusters application.email = params[:email] end + if application.has_attribute?(:stack) + application.stack = params[:stack] + end + if application.respond_to?(:oauth_application) application.oauth_application = create_oauth_application(application, request) end @@ -64,7 +68,7 @@ module Clusters end def invalid_application? - unknown_application? || (application_name == Applications::ElasticStack.application_name && !Feature.enabled?(:enable_cluster_application_elastic_stack)) + unknown_application? || (application_name == Applications::ElasticStack.application_name && !Feature.enabled?(:enable_cluster_application_elastic_stack)) || (application_name == Applications::Crossplane.application_name && !Feature.enabled?(:enable_cluster_application_crossplane)) end def unknown_application? diff --git a/app/views/clusters/clusters/show.html.haml b/app/views/clusters/clusters/show.html.haml index c5288c8d02d..5beeaf7259a 100644 --- a/app/views/clusters/clusters/show.html.haml +++ b/app/views/clusters/clusters/show.html.haml @@ -12,6 +12,7 @@ install_helm_path: clusterable.install_applications_cluster_path(@cluster, :helm), install_ingress_path: clusterable.install_applications_cluster_path(@cluster, :ingress), install_cert_manager_path: clusterable.install_applications_cluster_path(@cluster, :cert_manager), + install_crossplane_path: clusterable.install_applications_cluster_path(@cluster, :crossplane), install_prometheus_path: clusterable.install_applications_cluster_path(@cluster, :prometheus), install_runner_path: clusterable.install_applications_cluster_path(@cluster, :runner), install_jupyter_path: clusterable.install_applications_cluster_path(@cluster, :jupyter), diff --git a/changelogs/unreleased/18797-support-for-crossplane-as-a-managed-app.yml b/changelogs/unreleased/18797-support-for-crossplane-as-a-managed-app.yml new file mode 100644 index 00000000000..1f8d8093fdc --- /dev/null +++ b/changelogs/unreleased/18797-support-for-crossplane-as-a-managed-app.yml @@ -0,0 +1,5 @@ +--- +title: Support for Crossplane as a managed app +merge_request: 18797 +author: Mahendra Bagul +type: added diff --git a/db/migrate/20191017191341_create_clusters_applications_crossplane.rb b/db/migrate/20191017191341_create_clusters_applications_crossplane.rb new file mode 100644 index 00000000000..8dc25c56116 --- /dev/null +++ b/db/migrate/20191017191341_create_clusters_applications_crossplane.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class CreateClustersApplicationsCrossplane < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + create_table :clusters_applications_crossplane do |t| + t.timestamps_with_timezone null: false + t.references :cluster, null: false, index: false, foreign_key: { on_delete: :cascade } + t.integer :status, null: false + t.string :version, null: false, limit: 255 + t.string :stack, null: false, limit: 255 + t.text :status_reason + t.index :cluster_id, unique: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index a44388175c1..fd36599e1f9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1078,6 +1078,17 @@ ActiveRecord::Schema.define(version: 2019_11_14_173624) do t.index ["cluster_id"], name: "index_clusters_applications_cert_managers_on_cluster_id", unique: true end + create_table "clusters_applications_crossplane", id: :serial, force: :cascade do |t| + t.datetime_with_timezone "created_at", null: false + t.datetime_with_timezone "updated_at", null: false + t.bigint "cluster_id", null: false + t.integer "status", null: false + t.string "version", limit: 255, null: false + t.string "stack", limit: 255, null: false + t.text "status_reason" + t.index ["cluster_id"], name: "index_clusters_applications_crossplane_on_cluster_id", unique: true + end + create_table "clusters_applications_elastic_stacks", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false @@ -4222,6 +4233,7 @@ ActiveRecord::Schema.define(version: 2019_11_14_173624) do add_foreign_key "clusters", "projects", column: "management_project_id", name: "fk_f05c5e5a42", on_delete: :nullify add_foreign_key "clusters", "users", on_delete: :nullify add_foreign_key "clusters_applications_cert_managers", "clusters", on_delete: :cascade + add_foreign_key "clusters_applications_crossplane", "clusters", on_delete: :cascade add_foreign_key "clusters_applications_elastic_stacks", "clusters", on_delete: :cascade add_foreign_key "clusters_applications_helm", "clusters", on_delete: :cascade add_foreign_key "clusters_applications_ingress", "clusters", on_delete: :cascade diff --git a/doc/README.md b/doc/README.md index ac64d8df83d..af573a3eb34 100644 --- a/doc/README.md +++ b/doc/README.md @@ -305,7 +305,7 @@ The following documentation relates to the DevOps **Configure** stage: | Configure Topics | Description | |:-----------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------| | [Auto DevOps](topics/autodevops/index.md) | Automatically employ a complete DevOps lifecycle. | -| [Create Kubernetes clusters on GKE](user/project/clusters/add_remove_clusters.md#add-new-gke-cluster) | Use Google Kubernetes Engine and GitLab. | +| [Create Kubernetes clusters](user/project/clusters/add_remove_clusters.md#add-new-cluster) | Use Kubernetes and GitLab. | | [Executable Runbooks](user/project/clusters/runbooks/index.md) | Documented procedures that explain how to carry out particular processes. | | [GitLab ChatOps](ci/chatops/README.md) | Interact with CI/CD jobs through chat services. | | [Installing Applications](user/project/clusters/index.md#installing-applications) | Deploy Helm, Ingress, and Prometheus on Kubernetes. | diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 0aa0d18bf77..93549ac4de5 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -100,7 +100,7 @@ To make full use of Auto DevOps, you will need: To enable deployments, you will need: 1. A [Kubernetes 1.12+ cluster](../../user/project/clusters/index.md) for the project. The easiest - way is to add a [new GKE cluster using the GitLab UI](../../user/project/clusters/add_remove_clusters.md#add-new-gke-cluster). + way is to add a [new cluster using the GitLab UI](../../user/project/clusters/add_remove_clusters.md#add-new-cluster). 1. NGINX Ingress. You can deploy it to your Kubernetes cluster by installing the [GitLab-managed app for Ingress](../../user/clusters/applications.md#ingress), once you have configured GitLab's Kubernetes integration in the previous step. diff --git a/doc/user/project/clusters/add_remove_clusters.md b/doc/user/project/clusters/add_remove_clusters.md index 549dd4dd916..150a451dfe5 100644 --- a/doc/user/project/clusters/add_remove_clusters.md +++ b/doc/user/project/clusters/add_remove_clusters.md @@ -5,9 +5,6 @@ GitLab can integrate with the following Kubernetes providers: - Google Kubernetes Engine (GKE). - Amazon Elastic Kubernetes Service (EKS). -GitLab is more deeply integrated with GKE, but deeper integration with EKS -[is planned](https://gitlab.com/gitlab-org/gitlab/issues/22392). - TIP: **Tip:** Every new Google Cloud Platform (GCP) account receives [$300 in credit upon sign up](https://console.cloud.google.com/freetrial), and in partnership with Google, GitLab is able to offer an additional $200 for new GCP accounts to get started with GitLab's @@ -62,17 +59,17 @@ Note the following about access controls: GitLab creates the following resources for RBAC clusters. -| Name | Type | Details | Created when | -|:----------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:---------------------------| -| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster | -| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Creating a new GKE Cluster | -| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster | -| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | -| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller | -| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster | -| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster | -| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster | -| Environment namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster | +| Name | Type | Details | Created when | +|:----------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:-----------------------| +| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new cluster | +| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Creating a new cluster | +| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new cluster | +| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | +| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller | +| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster | +| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster | +| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster | +| Environment namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster | ### ABAC cluster resources @@ -80,13 +77,13 @@ GitLab creates the following resources for ABAC clusters. | Name | Type | Details | Created when | |:----------------------|:---------------------|:-------------------------------------|:---------------------------| -| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster | -| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster | -| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | -| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller | -| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster | -| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster | -| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster | +| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new cluster | +| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new cluster | +| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | +| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller | +| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster | +| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster | +| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster | ### Security of GitLab Runners @@ -112,7 +109,9 @@ If you don't want to use GitLab Runner in privileged mode, either: 1. Installing a Runner [using `docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html). -## Add new GKE cluster +## Add new cluster + +### GKE cluster GitLab supports: @@ -126,7 +125,7 @@ The [Google authentication integration](../../../integration/google.md) must be enabled in GitLab at the instance level. If that's not the case, ask your GitLab administrator to enable it. On GitLab.com, this is enabled. -### Requirements +#### GKE Requirements Before creating your first cluster on Google Kubernetes Engine with GitLab's integration, make sure the following requirements are met: @@ -151,7 +150,7 @@ order to setup an [initial service account](#access-controls). Starting from [Gi 11.10](https://gitlab.com/gitlab-org/gitlab-foss/issues/58208), the cluster creation process will explicitly request that basic authentication and client certificate is enabled. -### Creating the cluster +#### Creating the cluster on GKE If all of the above requirements are met, you can proceed to create and add a new Kubernetes cluster to your project: @@ -185,7 +184,7 @@ new Kubernetes cluster to your project: After a couple of minutes, your cluster will be ready to go. You can now proceed to install some [pre-defined applications](index.md#installing-applications). -### Cloud Run on GKE +#### Cloud Run on GKE > [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16566) in GitLab 12.4. @@ -194,6 +193,159 @@ separately after the cluster has been created. This means that Cloud Run (Knative), Istio, and HTTP Load Balancing will be enabled on the cluster at create time and cannot be [installed or uninstalled](../../clusters/applications.md) separately. +### EKS Cluster + +GitLab supports: + +- Creating a new EKS cluster using the GitLab UI + ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/22392) in GitLab 12.5). +- Providing credentials to add an [existing Kubernetes cluster](#add-existing-cluster). + +#### EKS Requirements + +Before creating your first cluster on Amazon EKS with GitLab's integration, +make sure the following requirements are met: + +- An [Amazon Web Services](https://aws.amazon.com/) account is set up and you are able to log in. +- You have permissions to manage IAM resources. + +##### Additional requirements for self-managed instances + +If you are using a self-managed GitLab instance, GitLab must first +be configured with a set of Amazon credentials. These credentials +will be used to assume an Amazon IAM role provided by the user +creating the cluster. Create an IAM user and ensure it has permissions +to assume the role(s) that your users will use to create EKS clusters. + +For example, the following policy document allows assuming a role whose name starts with +`gitlab-eks-` in account `123456789012`: + +```json +{ + "Version": "2012-10-17", + "Statement": { + "Effect": "Allow", + "Action": "sts:AssumeRole", + "Resource": "arn:aws:iam::123456789012:role/gitlab-eks-*" + } +} +``` + +Generate an access key for the IAM user, and configure GitLab with the credentials: + +1. Navigate to **Admin Area > Settings > Integrations** and expand the **Amazon EKS** section. +1. Check **Enable Amazon EKS integration**. +1. Enter the account ID and access key credentials into the respective + `Account ID`, `Access key ID` and `Secret access key` fields. +1. Click **Save changes**. + +#### Creating the cluster on EKS + +If all of the above requirements are met, you can proceed to create and add a +new Kubernetes cluster to your project: + +1. Navigate to your project's **Operations > Kubernetes** page. + + NOTE: **Note:** + You need Maintainer [permissions](../../permissions.md) and above to access the Kubernetes page. + +1. Click **Add Kubernetes cluster**. +1. Click **Amazon EKS**. You will be provided with an `Account ID` and `External ID` to use in the next step. +1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an IAM role: + 1. From the left panel, select **Roles**. + 1. Click **Create role**. + 1. Under `Select type of trusted entity`, select **Another AWS account**. + 1. Enter the Account ID from GitLab into the `Account ID` field. + 1. Check **Require external ID**. + 1. Enter the External ID from GitLab into the `External ID` field. + 1. Click **Next: Permissions**. + 1. Click **Create Policy**, which will open a new window. + 1. Select the **JSON** tab, and paste in the following snippet in place of the existing content: + + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "autoscaling:CreateAutoScalingGroup", + "autoscaling:DescribeAutoScalingGroups", + "autoscaling:DescribeScalingActivities", + "autoscaling:UpdateAutoScalingGroup", + "autoscaling:CreateLaunchConfiguration", + "autoscaling:DescribeLaunchConfigurations", + "cloudformation:CreateStack", + "cloudformation:DescribeStacks", + "ec2:AuthorizeSecurityGroupEgress", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:RevokeSecurityGroupEgress", + "ec2:RevokeSecurityGroupIngress", + "ec2:CreateSecurityGroup", + "ec2:createTags", + "ec2:DescribeImages", + "ec2:DescribeKeyPairs", + "ec2:DescribeRegions", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", + "eks:CreateCluster", + "eks:DescribeCluster", + "iam:AddRoleToInstanceProfile", + "iam:AttachRolePolicy", + "iam:CreateRole", + "iam:CreateInstanceProfile", + "iam:GetRole", + "iam:ListRoles", + "iam:PassRole", + "ssm:GetParameters" + ], + "Resource": "*" + } + ] + } + ``` + + NOTE: **Note:** + These permissions give GitLab the ability to create resources, but not delete them. + This means that if an error is encountered during the creation process, changes will + not be rolled back and you must remove resources manually. You can do this by deleting + the relevant [CloudFormation stack](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html) + + 1. Click **Review policy**. + 1. Enter a suitable name for this policy, and click **Create Policy**. You can now close this window. + 1. Switch back to the "Create role" window, and select the policy you just created. + 1. Click **Next: Tags**, and optionally enter any tags you wish to associate with this role. + 1. Click **Next: Review**. + 1. Enter a role name and optional description into the fields provided. + 1. Click **Create role**, the new role name will appear at the top. Click on its name and copy the `Role ARN` from the newly created role. +1. In GitLab, enter the copied role ARN into the `Role ARN` field. +1. Click **Authenticate with AWS**. +1. Choose your cluster's settings: + - **Kubernetes cluster name** - The name you wish to give the cluster. + - **Environment scope** - The [associated environment](index.md#setting-the-environment-scope-premium) to this cluster. + - **Kubernetes version** - The Kubernetes version to use. Currently the only version supported is 1.14. + - **Role name** - Select the [IAM role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) + to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. + - **Region** - The [region](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) + in which the cluster will be created. + - **Key pair name** - Select the [key pair](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) + that you can use to connect to your worker nodes if required. + - **VPC** - Select a [VPC](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html) + to use for your EKS Cluster resources. + - **Subnets** - Choose the [subnets](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html) + in your VPC where your worker nodes will run. + - **Security group** - Choose the [security group](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html) + to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets. + - **Instance type** - The [instance type](https://aws.amazon.com/ec2/instance-types/) of your worker nodes. + - **Node count** - The number of worker nodes. + - **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster. + See the [Managed clusters section](index.md#gitlab-managed-clusters) for more information. +1. Finally, click the **Create Kubernetes cluster** button. + +After about 10 minutes, your cluster will be ready to go. You can now proceed +to install some [pre-defined applications](index.md#installing-applications). + ## Add existing cluster If you have either of the following types of clusters already, you can add them to a project: diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md index 5e8ae5b0595..bffae4c5069 100644 --- a/doc/user/project/clusters/runbooks/index.md +++ b/doc/user/project/clusters/runbooks/index.md @@ -35,7 +35,7 @@ for an overview of how this is accomplished in GitLab!** To create an executable runbook, you will need: 1. **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the applications. - The simplest way to get started is to add a cluster using [GitLab's GKE integration](../add_remove_clusters.md#add-new-gke-cluster). + The simplest way to get started is to add a cluster using one of [GitLab's integrations](../add_remove_clusters.md#add-new-cluster). 1. **Helm Tiller** - Helm is a package manager for Kubernetes and is required to install all the other applications. It is installed in its own pod inside the cluster which can run the Helm CLI in a safe environment. @@ -60,7 +60,7 @@ the components outlined above and the preloaded demo runbook. ### 1. Add a Kubernetes cluster -Follow the steps outlined in [Add new GKE cluster](../add_remove_clusters.md#add-new-gke-cluster) +Follow the steps outlined in [Add new cluster](../add_remove_clusters.md#add-new-cluster) to add a Kubernetes cluster to your project. ### 2. Install Helm Tiller, Ingress, and JupyterHub diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md index 26db2133d09..ffd7b0c0f2a 100644 --- a/doc/user/project/clusters/serverless/index.md +++ b/doc/user/project/clusters/serverless/index.md @@ -41,7 +41,7 @@ To run Knative on GitLab, you will need: - If you are planning on deploying a serverless application, clone the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started. 1. **Kubernetes Cluster:** An RBAC-enabled Kubernetes cluster is required to deploy Knative. - The simplest way to get started is to add a cluster using [GitLab's GKE integration](../add_remove_clusters.md#add-new-gke-cluster). + The simplest way to get started is to add a cluster using [GitLab's GKE integration](../add_remove_clusters.md#gke-cluster). The set of minimum recommended cluster specifications to run Knative is 3 nodes, 6 vCPUs, and 22.50 GB memory. 1. **Helm Tiller:** Helm is a package manager for Kubernetes and is required to install Knative. @@ -64,6 +64,8 @@ To run Knative on GitLab, you will need: using our [runtimes](https://gitlab.com/gitlab-org/serverless/runtimes). 1. **Prometheus** (optional): Installing Prometheus allows you to monitor the scale and traffic of your serverless function/application. See [Installing Applications](../index.md#installing-applications) for more information. +1. **Logging** (optional): Configuring logging allows you to view and search request logs for your serverless function/application. + See [Configuring logging](#configuring-logging) for more information. ## Installing Knative via GitLab's Kubernetes integration @@ -166,13 +168,61 @@ You must do the following: or [serverless applications](#deploying-serverless-applications) onto your cluster. -## Deploying functions +## Configuring logging -> Introduced in GitLab 11.6. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/33330) in GitLab 12.5. + +### Prerequisites + +- A GitLab-managed cluster. +- `kubectl` installed and working. + +Running `kubectl` commands on your cluster requires setting up access to the +cluster first. For clusters created on: + +- GKE, see [GKE Cluster Access](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl) +- Other platforms, see [Install and Set Up kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/). + +### Enable request log template + +Run the following command to enable request logs: + +```shell +kubectl edit cm -n knative-serving config-observability +``` + +Copy the `logging.request-log-template` from the `data._example` field to the data field one level up in the hierarchy. + +### Enable request logs + +Run the following commands to install Elasticsearch, Kibana, and Filebeat into a `kube-logging` namespace and configure all nodes to forward logs using Filebeat: + +```shell +kubectl apply -f https://gitlab.com/gitlab-org/serverless/configurations/knative/raw/v0.7.0/kube-logging-filebeat.yaml +kubectl label nodes --all beta.kubernetes.io/filebeat-ready="true" +``` + +### Viewing request logs + +To view request logs: + +1. Run `kubectl proxy`. +1. Navigate to Kibana UI. + +Or: -Using functions is useful for dealing with independent events without needing -to maintain a complex unified infrastructure. This allows you to focus on a -single task that can be executed/scaled automatically and independently. +1. Open the Kibana UI. +1. Click on **Discover**, then select `filebeat-*` from the dropdown on the left. +1. Enter `kubernetes.container.name:"queue-proxy" AND message:/httpRequest/` into the search box. + +## Supported runtimes + +Serverless functions for GitLab can be written in 6 supported languages: + +- NodeJS and Ruby, with GitLab-managed and OpenFaas runtimes. +- C#, Go, PHP, and Python with OpenFaaS runtimes only. + +### GitLab managed runtimes Currently the following [runtimes](https://gitlab.com/gitlab-org/serverless/runtimes) are offered: @@ -182,6 +232,31 @@ Currently the following [runtimes](https://gitlab.com/gitlab-org/serverless/runt `Dockerfile` presence is assumed when a runtime is not specified. +### OpenFaaS runtimes + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/29253) in GitLab 12.5. + +[OpenFaaS classic runtimes](https://github.com/openfaas/templates#templates-in-store) can be used with GitLab serverless. +Runtimes are specified using the pattern: `openfaas/classic/<template_name>`. The following +example shows how to define a function in `serverless.yml` using an OpenFaaS runtime: + +```yaml +hello: + source: ./hello + runtime: openfaas/classic/ruby + description: "Ruby function using OpenFaaS classic runtime" +``` + +`handler` is not needed for OpenFaaS functions. The location of the handler is defined +by the conventions of the runtime. + +See the [`ruby-openfaas-function`](https://gitlab.com/knative-examples/ruby-openfaas-function) +project for an example of a function using an OpenFaaS runtime. + +## Deploying functions + +> Introduced in GitLab 11.6. + You can find and import all the files referenced in this doc in the **[functions example project](https://gitlab.com/knative-examples/functions)**. @@ -322,7 +397,7 @@ Running functions locally requires: - Go 1.12 or newer installed. - Docker Engine installed and running. - `gitlabktl` installed using the Go package manager: - + ```shell GO111MODULE=on go get gitlab.com/gitlab-org/gitlabktl ``` @@ -352,6 +427,10 @@ To run a function locally: > Introduced in GitLab 11.5. +Serverless applications are the building block of serverless functions. They are useful in scenarios where an existing +runtime does not meet the needs of an application, such as one written in a language that has no runtime available. Note +though that serverless applications should be stateless! + NOTE: **Note:** You can reference and import the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started. diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 5ad4f324a23..02afd42d9d3 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -73,6 +73,7 @@ module Gitlab clusters_applications_helm: count(::Clusters::Applications::Helm.available), clusters_applications_ingress: count(::Clusters::Applications::Ingress.available), clusters_applications_cert_managers: count(::Clusters::Applications::CertManager.available), + clusters_applications_crossplane: count(::Clusters::Applications::Crossplane.available), clusters_applications_prometheus: count(::Clusters::Applications::Prometheus.available), clusters_applications_runner: count(::Clusters::Applications::Runner.available), clusters_applications_knative: count(::Clusters::Applications::Knative.available), diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 1eb3a85f38d..17eab68b961 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1495,6 +1495,9 @@ msgstr "" msgid "Amazon EKS integration allows you to provision EKS clusters from GitLab." msgstr "" +msgid "Amazon Web Services" +msgstr "" + msgid "Amazon authentication is not %{link_start}correctly configured%{link_end}. Ask your GitLab administrator if you want to use this service." msgstr "" @@ -3646,6 +3649,12 @@ msgstr "" msgid "ClusterIntegration|Creating Kubernetes cluster" msgstr "" +msgid "ClusterIntegration|Crossplane" +msgstr "" + +msgid "ClusterIntegration|Crossplane enables declarative provisioning of managed services from your cloud of choice using %{kubectl} or %{gitlabIntegrationLink}. Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on." +msgstr "" + msgid "ClusterIntegration|Did you know?" msgstr "" @@ -3661,6 +3670,9 @@ msgstr "" msgid "ClusterIntegration|Enable this setting if using role-based access control (RBAC)." msgstr "" +msgid "ClusterIntegration|Enabled stack" +msgstr "" + msgid "ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster" msgstr "" @@ -3709,6 +3721,9 @@ msgstr "" msgid "ClusterIntegration|GitLab-managed cluster" msgstr "" +msgid "ClusterIntegration|Gitlab Integration" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project" msgstr "" @@ -4030,6 +4045,9 @@ msgstr "" msgid "ClusterIntegration|Select a region to choose a VPC" msgstr "" +msgid "ClusterIntegration|Select a stack to install Crossplane." +msgstr "" + msgid "ClusterIntegration|Select machine type" msgstr "" @@ -4982,6 +5000,9 @@ msgstr "" msgid "Cron syntax" msgstr "" +msgid "Crossplane" +msgstr "" + msgid "Current Branch" msgstr "" @@ -8442,6 +8463,9 @@ msgstr "" msgid "Golden Tanuki" msgstr "" +msgid "Google Cloud Platform" +msgstr "" + msgid "Google Code import" msgstr "" @@ -10885,6 +10909,9 @@ msgstr "" msgid "Metrics|e.g. req/sec" msgstr "" +msgid "Microsoft Azure" +msgstr "" + msgid "Migrated %{success_count}/%{total_count} files." msgstr "" @@ -14669,6 +14696,9 @@ msgstr "" msgid "Rollback" msgstr "" +msgid "Rook" +msgstr "" + msgid "Run CI/CD pipelines for external repositories" msgstr "" @@ -15243,6 +15273,9 @@ msgstr "" msgid "Select Page" msgstr "" +msgid "Select Stack" +msgstr "" + msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes." msgstr "" @@ -19854,6 +19887,9 @@ msgstr "" msgid "You must provide your current password in order to change it." msgstr "" +msgid "You must select a stack for configuring your cloud provider. Learn more about" +msgstr "" + msgid "You need a different license to enable FileLocks feature" msgstr "" diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index 09689b33a8c..0e59f8cb9ec 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -83,6 +83,11 @@ FactoryBot.define do cluster factory: %i(cluster with_installed_helm provided_by_gcp) end + factory :clusters_applications_crossplane, class: Clusters::Applications::Crossplane do + stack { 'gcp' } + cluster factory: %i(cluster with_installed_helm provided_by_gcp) + end + factory :clusters_applications_prometheus, class: Clusters::Applications::Prometheus do cluster factory: %i(cluster with_installed_helm provided_by_gcp) end diff --git a/spec/fixtures/api/schemas/cluster_status.json b/spec/fixtures/api/schemas/cluster_status.json index f3503f60e0c..f978baa2026 100644 --- a/spec/fixtures/api/schemas/cluster_status.json +++ b/spec/fixtures/api/schemas/cluster_status.json @@ -37,6 +37,7 @@ "hostname": { "type": ["string", "null"] }, "kibana_hostname": { "type": ["string", "null"] }, "email": { "type": ["string", "null"] }, + "stack": { "type": ["string", "null"] }, "update_available": { "type": ["boolean", "null"] }, "can_uninstall": { "type": "boolean" } }, diff --git a/spec/frontend/clusters/clusters_bundle_spec.js b/spec/frontend/clusters/clusters_bundle_spec.js index 317d3f3012b..199e11401a9 100644 --- a/spec/frontend/clusters/clusters_bundle_spec.js +++ b/spec/frontend/clusters/clusters_bundle_spec.js @@ -286,16 +286,21 @@ describe('Clusters', () => { }); describe('installApplication', () => { - it.each(APPLICATIONS)('tries to install %s', applicationId => { - jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce(); + it.each(APPLICATIONS)('tries to install %s', (applicationId, done) => { + jest.spyOn(cluster.service, 'installApplication').mockResolvedValue(); cluster.store.state.applications[applicationId].status = INSTALLABLE; - cluster.installApplication({ id: applicationId }); - - expect(cluster.store.state.applications[applicationId].status).toEqual(INSTALLING); - expect(cluster.store.state.applications[applicationId].requestReason).toEqual(null); - expect(cluster.service.installApplication).toHaveBeenCalledWith(applicationId, undefined); + // eslint-disable-next-line promise/valid-params + cluster + .installApplication({ id: applicationId }) + .then(() => { + expect(cluster.store.state.applications[applicationId].status).toEqual(INSTALLING); + expect(cluster.store.state.applications[applicationId].requestReason).toEqual(null); + expect(cluster.service.installApplication).toHaveBeenCalledWith(applicationId, undefined); + done(); + }) + .catch(); }); it('sets error request status when the request fails', () => { diff --git a/spec/frontend/clusters/components/applications_spec.js b/spec/frontend/clusters/components/applications_spec.js index a9435cef774..49bda9539fd 100644 --- a/spec/frontend/clusters/components/applications_spec.js +++ b/spec/frontend/clusters/components/applications_spec.js @@ -6,6 +6,7 @@ import { APPLICATIONS_MOCK_STATE } from '../services/mock_data'; import eventHub from '~/clusters/event_hub'; import { shallowMount } from '@vue/test-utils'; import KnativeDomainEditor from '~/clusters/components/knative_domain_editor.vue'; +import CrossplaneProviderStack from '~/clusters/components/crossplane_provider_stack.vue'; describe('Applications', () => { let vm; @@ -16,6 +17,7 @@ describe('Applications', () => { gon.features = gon.features || {}; gon.features.enableClusterApplicationElasticStack = true; + gon.features.enableClusterApplicationCrossplane = true; }); afterEach(() => { @@ -42,6 +44,10 @@ describe('Applications', () => { expect(vm.$el.querySelector('.js-cluster-application-row-cert_manager')).not.toBeNull(); }); + it('renders a row for Crossplane', () => { + expect(vm.$el.querySelector('.js-cluster-application-row-crossplane')).not.toBeNull(); + }); + it('renders a row for Prometheus', () => { expect(vm.$el.querySelector('.js-cluster-application-row-prometheus')).not.toBeNull(); }); @@ -83,6 +89,10 @@ describe('Applications', () => { expect(vm.$el.querySelector('.js-cluster-application-row-cert_manager')).not.toBeNull(); }); + it('renders a row for Crossplane', () => { + expect(vm.$el.querySelector('.js-cluster-application-row-crossplane')).not.toBeNull(); + }); + it('renders a row for Prometheus', () => { expect(vm.$el.querySelector('.js-cluster-application-row-prometheus')).not.toBeNull(); }); @@ -124,6 +134,10 @@ describe('Applications', () => { expect(vm.$el.querySelector('.js-cluster-application-row-cert_manager')).not.toBeNull(); }); + it('renders a row for Crossplane', () => { + expect(vm.$el.querySelector('.js-cluster-application-row-crossplane')).not.toBeNull(); + }); + it('renders a row for Prometheus', () => { expect(vm.$el.querySelector('.js-cluster-application-row-prometheus')).not.toBeNull(); }); @@ -179,6 +193,7 @@ describe('Applications', () => { }, helm: { title: 'Helm Tiller' }, cert_manager: { title: 'Cert-Manager' }, + crossplane: { title: 'Crossplane', stack: '' }, runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, jupyter: { title: 'JupyterHub', hostname: '' }, @@ -390,6 +405,32 @@ describe('Applications', () => { }); }); + describe('Crossplane application', () => { + const propsData = { + applications: { + ...APPLICATIONS_MOCK_STATE, + crossplane: { + title: 'Crossplane', + stack: { + code: '', + }, + }, + }, + }; + + let wrapper; + beforeEach(() => { + wrapper = shallowMount(Applications, { propsData }); + }); + afterEach(() => { + wrapper.destroy(); + }); + it('renders the correct Component', () => { + const crossplane = wrapper.find(CrossplaneProviderStack); + expect(crossplane.exists()).toBe(true); + }); + }); + describe('Elastic Stack application', () => { describe('with ingress installed with ip & elastic stack installable', () => { it('renders hostname active input', () => { diff --git a/spec/frontend/clusters/services/crossplane_provider_stack_spec.js b/spec/frontend/clusters/services/crossplane_provider_stack_spec.js new file mode 100644 index 00000000000..0d234822d7b --- /dev/null +++ b/spec/frontend/clusters/services/crossplane_provider_stack_spec.js @@ -0,0 +1,78 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlDropdownItem } from '@gitlab/ui'; +import CrossplaneProviderStack from '~/clusters/components/crossplane_provider_stack.vue'; + +describe('CrossplaneProviderStack component', () => { + let wrapper; + + const defaultProps = { + stacks: [ + { + name: 'Google Cloud Platform', + code: 'gcp', + }, + { + name: 'Amazon Web Services', + code: 'aws', + }, + ], + }; + + function createComponent(props = {}) { + const propsData = { + ...defaultProps, + ...props, + }; + + wrapper = shallowMount(CrossplaneProviderStack, { + propsData, + }); + } + + beforeEach(() => { + const crossplane = { + title: 'crossplane', + stack: '', + }; + createComponent({ crossplane }); + }); + + const findDropdownElements = () => wrapper.findAll(GlDropdownItem); + const findFirstDropdownElement = () => findDropdownElements().at(0); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders all of the available stacks in the dropdown', () => { + const dropdownElements = findDropdownElements(); + + expect(dropdownElements.length).toBe(defaultProps.stacks.length); + + defaultProps.stacks.forEach((stack, index) => + expect(dropdownElements.at(index).text()).toEqual(stack.name), + ); + }); + + it('displays the correct label for the first dropdown item if a stack is selected', () => { + const crossplane = { + title: 'crossplane', + stack: 'gcp', + }; + createComponent({ crossplane }); + expect(wrapper.vm.dropdownText).toBe('Google Cloud Platform'); + }); + + it('emits the "set" event with the selected stack value', () => { + const crossplane = { + title: 'crossplane', + stack: 'gcp', + }; + createComponent({ crossplane }); + findFirstDropdownElement().vm.$emit('click'); + expect(wrapper.emitted().set[0][0].code).toEqual('gcp'); + }); + it('it renders the correct dropdown text when no stack is selected', () => { + expect(wrapper.vm.dropdownText).toBe('Select Stack'); + }); +}); diff --git a/spec/frontend/clusters/services/mock_data.js b/spec/frontend/clusters/services/mock_data.js index e6feb89eecb..016f5a259b5 100644 --- a/spec/frontend/clusters/services/mock_data.js +++ b/spec/frontend/clusters/services/mock_data.js @@ -53,8 +53,14 @@ const CLUSTERS_MOCK_DATA = { can_uninstall: false, }, { + name: 'crossplane', + status: APPLICATION_STATUS.ERROR, + status_reason: 'Cannot connect', + can_uninstall: false, + }, + { name: 'elastic_stack', - status: APPLICATION_STATUS.INSTALLING, + status: APPLICATION_STATUS.ERROR, status_reason: 'Cannot connect', can_uninstall: false, }, @@ -105,6 +111,12 @@ const CLUSTERS_MOCK_DATA = { email: 'test@example.com', }, { + name: 'crossplane', + status: APPLICATION_STATUS.ERROR, + status_reason: 'Cannot connect', + stack: 'gcp', + }, + { name: 'elastic_stack', status: APPLICATION_STATUS.ERROR, status_reason: 'Cannot connect', @@ -116,6 +128,7 @@ const CLUSTERS_MOCK_DATA = { POST: { '/gitlab-org/gitlab-shell/clusters/1/applications/helm': {}, '/gitlab-org/gitlab-shell/clusters/1/applications/ingress': {}, + '/gitlab-org/gitlab-shell/clusters/1/applications/crossplane': {}, '/gitlab-org/gitlab-shell/clusters/1/applications/cert_manager': {}, '/gitlab-org/gitlab-shell/clusters/1/applications/runner': {}, '/gitlab-org/gitlab-shell/clusters/1/applications/prometheus': {}, @@ -138,6 +151,7 @@ const DEFAULT_APPLICATION_STATE = { const APPLICATIONS_MOCK_STATE = { helm: { title: 'Helm Tiller', status: 'installable' }, ingress: { title: 'Ingress', status: 'installable' }, + crossplane: { title: 'Crossplane', status: 'installable', stack: '' }, cert_manager: { title: 'Cert-Manager', status: 'installable' }, runner: { title: 'GitLab Runner' }, prometheus: { title: 'Prometheus' }, diff --git a/spec/frontend/clusters/stores/clusters_store_spec.js b/spec/frontend/clusters/stores/clusters_store_spec.js index 0e18a05f6c2..71d4daceb75 100644 --- a/spec/frontend/clusters/stores/clusters_store_spec.js +++ b/spec/frontend/clusters/stores/clusters_store_spec.js @@ -71,6 +71,7 @@ describe('Clusters Store', () => { uninstallable: false, uninstallSuccessful: false, uninstallFailed: false, + validationError: null, }, ingress: { title: 'Ingress', @@ -84,6 +85,7 @@ describe('Clusters Store', () => { uninstallable: false, uninstallSuccessful: false, uninstallFailed: false, + validationError: null, }, runner: { title: 'GitLab Runner', @@ -100,6 +102,7 @@ describe('Clusters Store', () => { uninstallable: false, uninstallSuccessful: false, uninstallFailed: false, + validationError: null, }, prometheus: { title: 'Prometheus', @@ -111,6 +114,7 @@ describe('Clusters Store', () => { uninstallable: false, uninstallSuccessful: false, uninstallFailed: false, + validationError: null, }, jupyter: { title: 'JupyterHub', @@ -123,6 +127,7 @@ describe('Clusters Store', () => { uninstallable: false, uninstallSuccessful: false, uninstallFailed: false, + validationError: null, }, knative: { title: 'Knative', @@ -140,6 +145,7 @@ describe('Clusters Store', () => { uninstallFailed: false, updateSuccessful: false, updateFailed: false, + validationError: null, }, cert_manager: { title: 'Cert-Manager', @@ -152,11 +158,12 @@ describe('Clusters Store', () => { uninstallable: false, uninstallSuccessful: false, uninstallFailed: false, + validationError: null, }, elastic_stack: { title: 'Elastic Stack', - status: mockResponseData.applications[7].status, - installFailed: false, + status: APPLICATION_STATUS.INSTALLABLE, + installFailed: true, statusReason: mockResponseData.applications[7].status_reason, requestReason: null, kibana_hostname: '', @@ -164,6 +171,19 @@ describe('Clusters Store', () => { uninstallable: false, uninstallSuccessful: false, uninstallFailed: false, + validationError: null, + }, + crossplane: { + title: 'Crossplane', + status: APPLICATION_STATUS.INSTALLABLE, + installFailed: true, + statusReason: mockResponseData.applications[8].status_reason, + requestReason: null, + installed: false, + uninstallable: false, + uninstallSuccessful: false, + uninstallFailed: false, + validationError: null, }, }, environments: [], diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index 790b0428d19..026fd1fedde 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Gfm::ReferenceRewriter do diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb index eef3b9de476..5a930d44dcb 100644 --- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Gfm::UploadsRewriter do diff --git a/spec/lib/gitlab/github_import/bulk_importing_spec.rb b/spec/lib/gitlab/github_import/bulk_importing_spec.rb index 91229d9c7d4..3266ec4ab50 100644 --- a/spec/lib/gitlab/github_import/bulk_importing_spec.rb +++ b/spec/lib/gitlab/github_import/bulk_importing_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::BulkImporting do diff --git a/spec/lib/gitlab/github_import/caching_spec.rb b/spec/lib/gitlab/github_import/caching_spec.rb index 70ecdc16da1..18c3e382532 100644 --- a/spec/lib/gitlab/github_import/caching_spec.rb +++ b/spec/lib/gitlab/github_import/caching_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Caching, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index 5b2642d9473..3b269d64b07 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Client do diff --git a/spec/lib/gitlab/github_import/importer/diff_note_importer_spec.rb b/spec/lib/gitlab/github_import/importer/diff_note_importer_spec.rb index 1568c657a1e..484458289af 100644 --- a/spec/lib/gitlab/github_import/importer/diff_note_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/diff_note_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::DiffNoteImporter do diff --git a/spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb b/spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb index 4713c6795bb..23ed21294e3 100644 --- a/spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::DiffNotesImporter do diff --git a/spec/lib/gitlab/github_import/importer/issue_and_label_links_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_and_label_links_importer_spec.rb index 665b31ef244..399e2d9a563 100644 --- a/spec/lib/gitlab/github_import/importer/issue_and_label_links_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/issue_and_label_links_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::IssueAndLabelLinksImporter do diff --git a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb index dab5767ece1..a003ad7e091 100644 --- a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/importer/issues_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issues_importer_spec.rb index e237e79e94b..8920ef9fedb 100644 --- a/spec/lib/gitlab/github_import/importer/issues_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/issues_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::IssuesImporter do diff --git a/spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb b/spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb index e2a71e78574..19d40b2f380 100644 --- a/spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::LabelLinksImporter do diff --git a/spec/lib/gitlab/github_import/importer/labels_importer_spec.rb b/spec/lib/gitlab/github_import/importer/labels_importer_spec.rb index 156ef96a0fa..2dcf1433154 100644 --- a/spec/lib/gitlab/github_import/importer/labels_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/labels_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::LabelsImporter, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb b/spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb index 8fd328d9c1e..a02b620f131 100644 --- a/spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::LfsObjectImporter do diff --git a/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb b/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb index 50442552eee..bec039a48eb 100644 --- a/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::LfsObjectsImporter do diff --git a/spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb b/spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb index 120a07ff2b3..eaf63e0e11b 100644 --- a/spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/importer/note_importer_spec.rb b/spec/lib/gitlab/github_import/importer/note_importer_spec.rb index 9bdcc42be19..d2b8ba186c8 100644 --- a/spec/lib/gitlab/github_import/importer/note_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/note_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::NoteImporter do diff --git a/spec/lib/gitlab/github_import/importer/notes_importer_spec.rb b/spec/lib/gitlab/github_import/importer/notes_importer_spec.rb index f046d13f879..128f8f95fa0 100644 --- a/spec/lib/gitlab/github_import/importer/notes_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/notes_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::NotesImporter do diff --git a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb index 8331f0b6bc7..50c27e7f4b7 100644 --- a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb index c51985f00a2..e2d810d5ddc 100644 --- a/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::PullRequestsImporter do diff --git a/spec/lib/gitlab/github_import/importer/releases_importer_spec.rb b/spec/lib/gitlab/github_import/importer/releases_importer_spec.rb index 6a31c57a73d..f8d53208619 100644 --- a/spec/lib/gitlab/github_import/importer/releases_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/releases_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::ReleasesImporter do diff --git a/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb b/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb index 705df1f4fe7..c65b28fafbf 100644 --- a/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Importer::RepositoryImporter do diff --git a/spec/lib/gitlab/github_import/issuable_finder_spec.rb b/spec/lib/gitlab/github_import/issuable_finder_spec.rb index da69911812a..b8a6feb6c73 100644 --- a/spec/lib/gitlab/github_import/issuable_finder_spec.rb +++ b/spec/lib/gitlab/github_import/issuable_finder_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/label_finder_spec.rb b/spec/lib/gitlab/github_import/label_finder_spec.rb index 8ba766944d6..039ae27ad57 100644 --- a/spec/lib/gitlab/github_import/label_finder_spec.rb +++ b/spec/lib/gitlab/github_import/label_finder_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::LabelFinder, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/markdown_text_spec.rb b/spec/lib/gitlab/github_import/markdown_text_spec.rb index 1ff5b9d66b3..a1216db7aac 100644 --- a/spec/lib/gitlab/github_import/markdown_text_spec.rb +++ b/spec/lib/gitlab/github_import/markdown_text_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::MarkdownText do diff --git a/spec/lib/gitlab/github_import/milestone_finder_spec.rb b/spec/lib/gitlab/github_import/milestone_finder_spec.rb index dff931a2fe8..407e2e67ec9 100644 --- a/spec/lib/gitlab/github_import/milestone_finder_spec.rb +++ b/spec/lib/gitlab/github_import/milestone_finder_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::MilestoneFinder, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/page_counter_spec.rb b/spec/lib/gitlab/github_import/page_counter_spec.rb index c2613a9a415..87f3ce45fd3 100644 --- a/spec/lib/gitlab/github_import/page_counter_spec.rb +++ b/spec/lib/gitlab/github_import/page_counter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::PageCounter, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/github_import/parallel_importer_spec.rb b/spec/lib/gitlab/github_import/parallel_importer_spec.rb index ecab64a372a..a9b7d3d388c 100644 --- a/spec/lib/gitlab/github_import/parallel_importer_spec.rb +++ b/spec/lib/gitlab/github_import/parallel_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::ParallelImporter do diff --git a/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb b/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb index 98205d3ee25..f4d107e3dce 100644 --- a/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb +++ b/spec/lib/gitlab/github_import/parallel_scheduling_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::ParallelScheduling do diff --git a/spec/lib/gitlab/github_import/representation/diff_note_spec.rb b/spec/lib/gitlab/github_import/representation/diff_note_spec.rb index 7b0a1ea4948..e743a87cdd1 100644 --- a/spec/lib/gitlab/github_import/representation/diff_note_spec.rb +++ b/spec/lib/gitlab/github_import/representation/diff_note_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Representation::DiffNote do diff --git a/spec/lib/gitlab/github_import/representation/expose_attribute_spec.rb b/spec/lib/gitlab/github_import/representation/expose_attribute_spec.rb index 15de0fe49ff..e3b48df4ae9 100644 --- a/spec/lib/gitlab/github_import/representation/expose_attribute_spec.rb +++ b/spec/lib/gitlab/github_import/representation/expose_attribute_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Representation::ExposeAttribute do diff --git a/spec/lib/gitlab/github_import/representation/issue_spec.rb b/spec/lib/gitlab/github_import/representation/issue_spec.rb index 99330ce42cb..741a912e53b 100644 --- a/spec/lib/gitlab/github_import/representation/issue_spec.rb +++ b/spec/lib/gitlab/github_import/representation/issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Representation::Issue do diff --git a/spec/lib/gitlab/github_import/representation/note_spec.rb b/spec/lib/gitlab/github_import/representation/note_spec.rb index f2c1c66b357..a171a38bc9e 100644 --- a/spec/lib/gitlab/github_import/representation/note_spec.rb +++ b/spec/lib/gitlab/github_import/representation/note_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Representation::Note do diff --git a/spec/lib/gitlab/github_import/representation/pull_request_spec.rb b/spec/lib/gitlab/github_import/representation/pull_request_spec.rb index d478e5ae899..b6dcd098c9c 100644 --- a/spec/lib/gitlab/github_import/representation/pull_request_spec.rb +++ b/spec/lib/gitlab/github_import/representation/pull_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Representation::PullRequest do diff --git a/spec/lib/gitlab/github_import/representation/to_hash_spec.rb b/spec/lib/gitlab/github_import/representation/to_hash_spec.rb index c296aa0a45b..9c47349b376 100644 --- a/spec/lib/gitlab/github_import/representation/to_hash_spec.rb +++ b/spec/lib/gitlab/github_import/representation/to_hash_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Representation::ToHash do diff --git a/spec/lib/gitlab/github_import/representation/user_spec.rb b/spec/lib/gitlab/github_import/representation/user_spec.rb index 4e63e8ea568..a7ad6bda3ad 100644 --- a/spec/lib/gitlab/github_import/representation/user_spec.rb +++ b/spec/lib/gitlab/github_import/representation/user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Representation::User do diff --git a/spec/lib/gitlab/github_import/representation_spec.rb b/spec/lib/gitlab/github_import/representation_spec.rb index 0b0610817b0..76753a0ff21 100644 --- a/spec/lib/gitlab/github_import/representation_spec.rb +++ b/spec/lib/gitlab/github_import/representation_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::Representation do diff --git a/spec/lib/gitlab/github_import/sequential_importer_spec.rb b/spec/lib/gitlab/github_import/sequential_importer_spec.rb index 05d3243f806..8b1e8fbf3b7 100644 --- a/spec/lib/gitlab/github_import/sequential_importer_spec.rb +++ b/spec/lib/gitlab/github_import/sequential_importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::SequentialImporter do diff --git a/spec/lib/gitlab/github_import/user_finder_spec.rb b/spec/lib/gitlab/github_import/user_finder_spec.rb index 29f4c00d9c7..74b5c1c52cd 100644 --- a/spec/lib/gitlab/github_import/user_finder_spec.rb +++ b/spec/lib/gitlab/github_import/user_finder_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 7a5c2a29d89..343e70b6dea 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -44,6 +44,7 @@ describe Gitlab::UsageData do create(:clusters_applications_ingress, :installed, cluster: gcp_cluster) create(:clusters_applications_cert_manager, :installed, cluster: gcp_cluster) create(:clusters_applications_prometheus, :installed, cluster: gcp_cluster) + create(:clusters_applications_crossplane, :installed, cluster: gcp_cluster) create(:clusters_applications_runner, :installed, cluster: gcp_cluster) create(:clusters_applications_knative, :installed, cluster: gcp_cluster) create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster) @@ -140,6 +141,7 @@ describe Gitlab::UsageData do clusters_applications_ingress clusters_applications_cert_managers clusters_applications_prometheus + clusters_applications_crossplane clusters_applications_runner clusters_applications_knative clusters_applications_elastic_stack @@ -222,6 +224,7 @@ describe Gitlab::UsageData do expect(count_data[:clusters_applications_helm]).to eq(1) expect(count_data[:clusters_applications_ingress]).to eq(1) expect(count_data[:clusters_applications_cert_managers]).to eq(1) + expect(count_data[:clusters_applications_crossplane]).to eq(1) expect(count_data[:clusters_applications_prometheus]).to eq(1) expect(count_data[:clusters_applications_runner]).to eq(1) expect(count_data[:clusters_applications_knative]).to eq(1) diff --git a/spec/models/clusters/applications/crossplane_spec.rb b/spec/models/clusters/applications/crossplane_spec.rb new file mode 100644 index 00000000000..ebc675497f4 --- /dev/null +++ b/spec/models/clusters/applications/crossplane_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Clusters::Applications::Crossplane do + let(:crossplane) { create(:clusters_applications_crossplane) } + + include_examples 'cluster application core specs', :clusters_applications_crossplane + include_examples 'cluster application status specs', :clusters_applications_crossplane + include_examples 'cluster application version specs', :clusters_applications_crossplane + include_examples 'cluster application initial status specs' + + describe 'validations' do + it { is_expected.to validate_presence_of(:stack) } + end + + describe '#can_uninstall?' do + subject { crossplane.can_uninstall? } + + it { is_expected.to be_truthy } + end + + describe '#install_command' do + let(:stack) { 'gcp' } + + subject { crossplane.install_command } + + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + + it 'is initialized with crossplane arguments' do + expect(subject.name).to eq('crossplane') + expect(subject.chart).to eq('crossplane/crossplane') + expect(subject.repository).to eq('https://charts.crossplane.io/alpha') + expect(subject.version).to eq('0.4.1') + expect(subject).to be_rbac + end + + context 'application failed to install previously' do + let(:crossplane) { create(:clusters_applications_crossplane, :errored, version: '0.0.1') } + + it 'is initialized with the locked version' do + expect(subject.version).to eq('0.4.1') + end + end + end + + describe '#files' do + let(:application) { crossplane } + let(:values) { subject[:'values.yaml'] } + + subject { application.files } + + it 'includes crossplane specific keys in the values.yaml file' do + expect(values).to include('clusterStacks') + end + end +end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 253866c8425..a163229e15a 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -515,6 +515,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do let!(:helm) { create(:clusters_applications_helm, cluster: cluster) } let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) } let!(:cert_manager) { create(:clusters_applications_cert_manager, cluster: cluster) } + let!(:crossplane) { create(:clusters_applications_crossplane, cluster: cluster) } let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) } let!(:runner) { create(:clusters_applications_runner, cluster: cluster) } let!(:jupyter) { create(:clusters_applications_jupyter, cluster: cluster) } @@ -522,7 +523,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do let!(:elastic_stack) { create(:clusters_applications_elastic_stack, cluster: cluster) } it 'returns a list of created applications' do - is_expected.to contain_exactly(helm, ingress, cert_manager, prometheus, runner, jupyter, knative, elastic_stack) + is_expected.to contain_exactly(helm, ingress, cert_manager, crossplane, prometheus, runner, jupyter, knative, elastic_stack) end end end diff --git a/vendor/crossplane/values.yaml b/vendor/crossplane/values.yaml new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/vendor/crossplane/values.yaml |