summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-11-18 03:06:28 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-11-18 03:06:28 +0000
commitc1f270b8ba4602952c36ce042e5eae439b22f9a6 (patch)
tree205917e3dc8dcaeaaa0de55e2618eaca4197c4c2
parent7f4a1ba886819078d1fa0bfc348e3743f0e2b2f2 (diff)
downloadgitlab-ce-c1f270b8ba4602952c36ce042e5eae439b22f9a6.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/images/cluster_app_logos/crossplane.pngbin0 -> 1850 bytes
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js47
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue113
-rw-r--r--app/assets/javascripts/clusters/components/crossplane_provider_stack.vue93
-rw-r--r--app/assets/javascripts/clusters/constants.js1
-rw-r--r--app/assets/javascripts/clusters/services/clusters_service.js1
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js10
-rw-r--r--app/controllers/clusters/applications_controller.rb2
-rw-r--r--app/controllers/clusters/clusters_controller.rb1
-rw-r--r--app/models/clusters/applications/crossplane.rb60
-rw-r--r--app/models/clusters/cluster.rb2
-rw-r--r--app/serializers/cluster_application_entity.rb1
-rw-r--r--app/services/clusters/applications/base_service.rb6
-rw-r--r--app/views/clusters/clusters/show.html.haml1
-rw-r--r--changelogs/unreleased/18797-support-for-crossplane-as-a-managed-app.yml5
-rw-r--r--db/migrate/20191017191341_create_clusters_applications_crossplane.rb19
-rw-r--r--db/schema.rb12
-rw-r--r--doc/README.md2
-rw-r--r--doc/topics/autodevops/index.md2
-rw-r--r--doc/user/project/clusters/add_remove_clusters.md202
-rw-r--r--doc/user/project/clusters/runbooks/index.md4
-rw-r--r--doc/user/project/clusters/serverless/index.md93
-rw-r--r--lib/gitlab/usage_data.rb1
-rw-r--r--locale/gitlab.pot36
-rw-r--r--spec/factories/clusters/applications/helm.rb5
-rw-r--r--spec/fixtures/api/schemas/cluster_status.json1
-rw-r--r--spec/frontend/clusters/clusters_bundle_spec.js19
-rw-r--r--spec/frontend/clusters/components/applications_spec.js41
-rw-r--r--spec/frontend/clusters/services/crossplane_provider_stack_spec.js78
-rw-r--r--spec/frontend/clusters/services/mock_data.js16
-rw-r--r--spec/frontend/clusters/stores/clusters_store_spec.js24
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb2
-rw-r--r--spec/lib/gitlab/gfm/uploads_rewriter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/bulk_importing_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/caching_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/diff_note_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/issue_and_label_links_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/issue_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/issues_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/labels_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/note_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/notes_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/releases_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer/repository_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/issuable_finder_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/label_finder_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/markdown_text_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/milestone_finder_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/page_counter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/parallel_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/parallel_scheduling_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/representation/diff_note_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/representation/expose_attribute_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/representation/issue_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/representation/note_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/representation/pull_request_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/representation/to_hash_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/representation/user_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/representation_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/sequential_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/user_finder_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb3
-rw-r--r--spec/models/clusters/applications/crossplane_spec.rb57
-rw-r--r--spec/models/clusters/cluster_spec.rb3
-rw-r--r--vendor/crossplane/values.yaml0
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
new file mode 100644
index 00000000000..32d8175108c
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/crossplane.png
Binary files differ
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