diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-18 03:06:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-18 03:06:28 +0000 |
commit | c1f270b8ba4602952c36ce042e5eae439b22f9a6 (patch) | |
tree | 205917e3dc8dcaeaaa0de55e2618eaca4197c4c2 /app/assets | |
parent | 7f4a1ba886819078d1fa0bfc348e3743f0e2b2f2 (diff) | |
download | gitlab-ce-c1f270b8ba4602952c36ce042e5eae439b22f9a6.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r-- | app/assets/images/cluster_app_logos/crossplane.png | bin | 0 -> 1850 bytes | |||
-rw-r--r-- | app/assets/javascripts/clusters/clusters_bundle.js | 47 | ||||
-rw-r--r-- | app/assets/javascripts/clusters/components/applications.vue | 113 | ||||
-rw-r--r-- | app/assets/javascripts/clusters/components/crossplane_provider_stack.vue | 93 | ||||
-rw-r--r-- | app/assets/javascripts/clusters/constants.js | 1 | ||||
-rw-r--r-- | app/assets/javascripts/clusters/services/clusters_service.js | 1 | ||||
-rw-r--r-- | app/assets/javascripts/clusters/stores/clusters_store.js | 10 |
7 files changed, 230 insertions, 35 deletions
diff --git a/app/assets/images/cluster_app_logos/crossplane.png b/app/assets/images/cluster_app_logos/crossplane.png Binary files differnew file mode 100644 index 00000000000..32d8175108c --- /dev/null +++ b/app/assets/images/cluster_app_logos/crossplane.png diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index d471dcb1b06..75909dd9d20 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -8,7 +8,7 @@ import Flash from '../flash'; import Poll from '../lib/utils/poll'; import initSettingsPanels from '../settings_panels'; import eventHub from './event_hub'; -import { APPLICATION_STATUS, INGRESS, INGRESS_DOMAIN_SUFFIX } from './constants'; +import { APPLICATION_STATUS, INGRESS, INGRESS_DOMAIN_SUFFIX, CROSSPLANE } from './constants'; import ClustersService from './services/clusters_service'; import ClustersStore from './stores/clusters_store'; import Applications from './components/applications.vue'; @@ -39,6 +39,7 @@ export default class Clusters { installKnativePath, updateKnativePath, installElasticStackPath, + installCrossplanePath, installPrometheusPath, managePrometheusPath, clusterEnvironmentsPath, @@ -83,6 +84,7 @@ export default class Clusters { installHelmEndpoint: installHelmPath, installIngressEndpoint: installIngressPath, installCertManagerEndpoint: installCertManagerPath, + installCrossplaneEndpoint: installCrossplanePath, installRunnerEndpoint: installRunnerPath, installPrometheusEndpoint: installPrometheusPath, installJupyterEndpoint: installJupyterPath, @@ -227,6 +229,7 @@ export default class Clusters { eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data)); eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data)); eventHub.$on('uninstallApplication', data => this.uninstallApplication(data)); + eventHub.$on('setCrossplaneProviderStack', data => this.setCrossplaneProviderStack(data)); // Add event listener to all the banner close buttons this.addBannerCloseHandler(this.unreachableContainer, 'unreachable'); this.addBannerCloseHandler(this.authenticationFailureContainer, 'authentication_failure'); @@ -238,6 +241,7 @@ export default class Clusters { eventHub.$off('updateApplication', this.updateApplication); eventHub.$off('saveKnativeDomain'); eventHub.$off('setKnativeHostname'); + eventHub.$off('setCrossplaneProviderStack'); eventHub.$off('uninstallApplication'); } @@ -404,18 +408,33 @@ export default class Clusters { } installApplication({ id: appId, params }) { - this.store.updateAppProperty(appId, 'requestReason', null); - this.store.updateAppProperty(appId, 'statusReason', null); + return Clusters.validateInstallation(appId, params) + .then(() => { + this.store.updateAppProperty(appId, 'requestReason', null); + this.store.updateAppProperty(appId, 'statusReason', null); + this.store.installApplication(appId); + + // eslint-disable-next-line promise/no-nesting + this.service.installApplication(appId, params).catch(() => { + this.store.notifyInstallFailure(appId); + this.store.updateAppProperty( + appId, + 'requestReason', + s__('ClusterIntegration|Request to begin installing failed'), + ); + }); + }) + .catch(error => this.store.updateAppProperty(appId, 'validationError', error)); + } - this.store.installApplication(appId); + static validateInstallation(appId, params) { + return new Promise((resolve, reject) => { + if (appId === CROSSPLANE && !params.stack) { + reject(s__('ClusterIntegration|Select a stack to install Crossplane.')); + return; + } - return this.service.installApplication(appId, params).catch(() => { - this.store.notifyInstallFailure(appId); - this.store.updateAppProperty( - appId, - 'requestReason', - s__('ClusterIntegration|Request to begin installing failed'), - ); + resolve(); }); } @@ -463,6 +482,12 @@ export default class Clusters { this.store.updateAppProperty(appId, 'hostname', data.hostname); } + setCrossplaneProviderStack(data) { + const appId = data.id; + this.store.updateAppProperty(appId, 'stack', data.stack.code); + this.store.updateAppProperty(appId, 'validationError', null); + } + destroy() { this.destroyed = true; diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 44d77277cc5..a951a6bfeea 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -9,6 +9,7 @@ import jeagerLogo from 'images/cluster_app_logos/jeager.png'; import jupyterhubLogo from 'images/cluster_app_logos/jupyterhub.png'; import kubernetesLogo from 'images/cluster_app_logos/kubernetes.png'; import certManagerLogo from 'images/cluster_app_logos/cert_manager.png'; +import crossplaneLogo from 'images/cluster_app_logos/crossplane.png'; import knativeLogo from 'images/cluster_app_logos/knative.png'; import meltanoLogo from 'images/cluster_app_logos/meltano.png'; import prometheusLogo from 'images/cluster_app_logos/prometheus.png'; @@ -20,6 +21,7 @@ import KnativeDomainEditor from './knative_domain_editor.vue'; import { CLUSTER_TYPE, PROVIDER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; import eventHub from '~/clusters/event_hub'; +import CrossplaneProviderStack from './crossplane_provider_stack.vue'; export default { components: { @@ -28,6 +30,7 @@ export default { LoadingButton, GlLoadingIcon, KnativeDomainEditor, + CrossplaneProviderStack, }, props: { type: { @@ -89,6 +92,7 @@ export default { jupyterhubLogo, kubernetesLogo, certManagerLogo, + crossplaneLogo, knativeLogo, meltanoLogo, prometheusLogo, @@ -116,6 +120,12 @@ export default { certManagerInstalled() { return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED; }, + crossplaneInstalled() { + return this.applications.crossplane.status === APPLICATION_STATUS.INSTALLED; + }, + enableClusterApplicationCrossplane() { + return gon.features && gon.features.enableClusterApplicationCrossplane; + }, enableClusterApplicationElasticStack() { return gon.features && gon.features.enableClusterApplicationElasticStack; }, @@ -151,6 +161,24 @@ export default { false, ); }, + crossplaneDescription() { + return sprintf( + _.escape( + s__( + `ClusterIntegration|Crossplane enables declarative provisioning of managed services from your cloud of choice using %{kubectl} or %{gitlabIntegrationLink}. +Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on.`, + ), + ), + { + gitlabIntegrationLink: `<a href="https://docs.gitlab.com/ce/user/project/integrations/crossplane.html" + target="_blank" rel="noopener noreferrer"> + ${_.escape(s__('ClusterIntegration|Gitlab Integration'))}</a>`, + kubectl: `<code>kubectl</code>`, + }, + false, + ); + }, + prometheusDescription() { return sprintf( _.escape( @@ -182,6 +210,9 @@ export default { knative() { return this.applications.knative; }, + crossplane() { + return this.applications.crossplane; + }, cloudRun() { return this.providerType === PROVIDER_TYPE.GCP && this.preInstalledKnative; }, @@ -218,6 +249,12 @@ export default { hostname, }); }, + setCrossplaneProviderStack(stack) { + eventHub.$emit('setCrossplaneProviderStack', { + id: 'crossplane', + stack, + }); + }, }, }; </script> @@ -228,7 +265,7 @@ export default { <p class="append-bottom-0"> {{ s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster. - Helm Tiller is required to install any of the following applications.`) + Helm Tiller is required to install any of the following applications.`) }} <a :href="helpPath">{{ __('More information') }}</a> </p> @@ -253,9 +290,9 @@ export default { <div slot="description"> {{ s__(`ClusterIntegration|Helm streamlines installing - and managing Kubernetes applications. - Tiller runs inside of your Kubernetes Cluster, - and manages releases of your charts.`) + and managing Kubernetes applications. + Tiller runs inside of your Kubernetes Cluster, + and manages releases of your charts.`) }} </div> </application-row> @@ -263,7 +300,7 @@ export default { <div class="svg-container" v-html="helmInstallIllustration"></div> {{ s__(`ClusterIntegration|You must first install Helm Tiller before - installing the applications below`) + installing the applications below`) }} </div> <application-row @@ -286,8 +323,8 @@ export default { <p> {{ s__(`ClusterIntegration|Ingress gives you a way to route - requests to services based on the request host or path, - centralizing a number of services into a single entrypoint.`) + requests to services based on the request host or path, + centralizing a number of services into a single entrypoint.`) }} </p> @@ -319,8 +356,8 @@ export default { <p class="form-text text-muted"> {{ s__(`ClusterIntegration|Point a wildcard DNS to this - generated endpoint in order to access - your application after it has been deployed.`) + generated endpoint in order to access + your application after it has been deployed.`) }} <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> {{ __('More information') }} @@ -331,8 +368,8 @@ export default { <p v-if="!ingressExternalEndpoint" class="settings-message js-no-endpoint-message"> {{ s__(`ClusterIntegration|The endpoint is in - the process of being assigned. Please check your Kubernetes - cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) + the process of being assigned. Please check your Kubernetes + cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) }} <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> {{ __('More information') }} @@ -379,7 +416,7 @@ export default { <p class="form-text text-muted"> {{ s__(`ClusterIntegration|Issuers represent a certificate authority. - You must provide an email address for your Issuer. `) + You must provide an email address for your Issuer. `) }} <a href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email" @@ -435,13 +472,41 @@ export default { <div slot="description"> {{ s__(`ClusterIntegration|GitLab Runner connects to the - repository and executes CI/CD jobs, - pushing results back and deploying - applications to production.`) + repository and executes CI/CD jobs, + pushing results back and deploying + applications to production.`) }} </div> </application-row> <application-row + v-if="enableClusterApplicationCrossplane" + id="crossplane" + :logo-url="crossplaneLogo" + :title="applications.crossplane.title" + :status="applications.crossplane.status" + :status-reason="applications.crossplane.statusReason" + :request-status="applications.crossplane.requestStatus" + :request-reason="applications.crossplane.requestReason" + :installed="applications.crossplane.installed" + :install-failed="applications.crossplane.installFailed" + :uninstallable="applications.crossplane.uninstallable" + :uninstall-successful="applications.crossplane.uninstallSuccessful" + :uninstall-failed="applications.crossplane.uninstallFailed" + :install-application-request-params="{ stack: applications.crossplane.stack }" + :disabled="!helmInstalled" + title-link="https://crossplane.io" + > + <template> + <div slot="description"> + <p v-html="crossplaneDescription"></p> + <div class="form-group"> + <CrossplaneProviderStack :crossplane="crossplane" @set="setCrossplaneProviderStack" /> + </div> + </div> + </template> + </application-row> + + <application-row id="jupyter" :logo-url="jupyterhubLogo" :title="applications.jupyter.title" @@ -462,10 +527,10 @@ export default { <p> {{ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns, - manages, and proxies multiple instances of the single-user - Jupyter notebook server. JupyterHub can be used to serve - notebooks to a class of students, a corporate data science group, - or a scientific research group.`) + manages, and proxies multiple instances of the single-user + Jupyter notebook server. JupyterHub can be used to serve + notebooks to a class of students, a corporate data science group, + or a scientific research group.`) }} </p> @@ -492,7 +557,7 @@ export default { <p v-if="ingressInstalled" class="form-text text-muted"> {{ s__(`ClusterIntegration|Replace this with your own hostname if you want. - If you do so, point hostname to Ingress IP Address from above.`) + If you do so, point hostname to Ingress IP Address from above.`) }} <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> {{ __('More information') }} @@ -538,9 +603,9 @@ export default { <p> {{ s__(`ClusterIntegration|Knative extends Kubernetes to provide - a set of middleware components that are essential to build modern, - source-centric, and container-based applications that can run - anywhere: on premises, in the cloud, or even in a third-party data center.`) + a set of middleware components that are essential to build modern, + source-centric, and container-based applications that can run + anywhere: on premises, in the cloud, or even in a third-party data center.`) }} </p> @@ -612,7 +677,7 @@ export default { <p v-if="ingressInstalled" class="form-text text-muted"> {{ s__(`ClusterIntegration|Replace this with your own hostname if you want. - If you do so, point hostname to Ingress IP Address from above.`) + If you do so, point hostname to Ingress IP Address from above.`) }} <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> {{ __('More information') }} diff --git a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue new file mode 100644 index 00000000000..966918ae636 --- /dev/null +++ b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue @@ -0,0 +1,93 @@ +<script> +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import Icon from '~/vue_shared/components/icon.vue'; +import { s__ } from '../../locale'; + +export default { + name: 'CrossplaneProviderStack', + components: { + GlDropdown, + GlDropdownItem, + Icon, + }, + props: { + stacks: { + type: Array, + required: false, + default: () => [ + { + name: s__('Google Cloud Platform'), + code: 'gcp', + }, + { + name: s__('Amazon Web Services'), + code: 'aws', + }, + { + name: s__('Microsoft Azure'), + code: 'azure', + }, + { + name: s__('Rook'), + code: 'rook', + }, + ], + }, + crossplane: { + type: Object, + required: true, + }, + }, + computed: { + dropdownText() { + const result = this.stacks.reduce((map, obj) => { + // eslint-disable-next-line no-param-reassign + map[obj.code] = obj.name; + return map; + }, {}); + const { stack } = this.crossplane; + if (stack !== '') { + return result[stack]; + } + return s__('Select Stack'); + }, + validationError() { + return this.crossplane.validationError; + }, + }, + methods: { + selectStack(stack) { + this.$emit('set', stack); + }, + }, +}; +</script> + +<template> + <div> + <label> + {{ s__('ClusterIntegration|Enabled stack') }} + </label> + <gl-dropdown + :disabled="crossplane.installed" + :text="dropdownText" + toggle-class="dropdown-menu-toggle gl-field-error-outline" + class="w-100" + :class="{ 'gl-show-field-errors': validationError }" + > + <gl-dropdown-item v-for="stack in stacks" :key="stack.code" @click="selectStack(stack)"> + <span class="ml-1">{{ stack.name }}</span> + </gl-dropdown-item> + </gl-dropdown> + <span v-if="validationError" class="gl-field-error">{{ validationError }}</span> + <p class="form-text text-muted"> + {{ s__(`You must select a stack for configuring your cloud provider. Learn more about`) }} + <a + href="https://crossplane.io/docs/master/stacks-guide.html" + target="_blank" + rel="noopener noreferrer" + >{{ __('Crossplane') }}</a + > + </p> + </div> +</template> diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js index d7152e32376..9f98f170fb0 100644 --- a/app/assets/javascripts/clusters/constants.js +++ b/app/assets/javascripts/clusters/constants.js @@ -50,6 +50,7 @@ export const JUPYTER = 'jupyter'; export const KNATIVE = 'knative'; export const RUNNER = 'runner'; export const CERT_MANAGER = 'cert_manager'; +export const CROSSPLANE = 'crossplane'; export const PROMETHEUS = 'prometheus'; export const ELASTIC_STACK = 'elastic_stack'; diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js index dab4da04bf3..333fb293a15 100644 --- a/app/assets/javascripts/clusters/services/clusters_service.js +++ b/app/assets/javascripts/clusters/services/clusters_service.js @@ -7,6 +7,7 @@ export default class ClusterService { helm: this.options.installHelmEndpoint, ingress: this.options.installIngressEndpoint, cert_manager: this.options.installCertManagerEndpoint, + crossplane: this.options.installCrossplaneEndpoint, runner: this.options.installRunnerEndpoint, prometheus: this.options.installPrometheusEndpoint, jupyter: this.options.installJupyterEndpoint, diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index 6304e81c296..35dbf951551 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -6,6 +6,7 @@ import { KNATIVE, CERT_MANAGER, ELASTIC_STACK, + CROSSPLANE, RUNNER, APPLICATION_INSTALLED_STATUSES, APPLICATION_STATUS, @@ -26,6 +27,7 @@ const applicationInitialState = { uninstallable: false, uninstallFailed: false, uninstallSuccessful: false, + validationError: null, }; export default class ClusterStore { @@ -58,6 +60,11 @@ export default class ClusterStore { title: s__('ClusterIntegration|Cert-Manager'), email: null, }, + crossplane: { + ...applicationInitialState, + title: s__('ClusterIntegration|Crossplane'), + stack: null, + }, runner: { ...applicationInitialState, title: s__('ClusterIntegration|GitLab Runner'), @@ -203,6 +210,9 @@ export default class ClusterStore { } else if (appId === CERT_MANAGER) { this.state.applications.cert_manager.email = this.state.applications.cert_manager.email || serverAppEntry.email; + } else if (appId === CROSSPLANE) { + this.state.applications.crossplane.stack = + this.state.applications.crossplane.stack || serverAppEntry.stack; } else if (appId === JUPYTER) { this.state.applications.jupyter.hostname = this.updateHostnameIfUnset( this.state.applications.jupyter.hostname, |