app/assets/images/cluster_app_logos/crossplane.png

1.81 KiB

...@@ -8,7 +8,7 @@ import Flash from '../flash'; ...@@ -8,7 +8,7 @@ import Flash from '../flash';
import Poll from '../lib/utils/poll'; import Poll from '../lib/utils/poll';
import initSettingsPanels from '../settings_panels'; import initSettingsPanels from '../settings_panels';
import eventHub from './event_hub'; 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 ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store'; import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue'; import Applications from './components/applications.vue';
...@@ -39,6 +39,7 @@ export default class Clusters { ...@@ -39,6 +39,7 @@ export default class Clusters {
installKnativePath, installKnativePath,
updateKnativePath, updateKnativePath,
installElasticStackPath, installElasticStackPath,
installCrossplanePath,
installPrometheusPath, installPrometheusPath,
managePrometheusPath, managePrometheusPath,
clusterEnvironmentsPath, clusterEnvironmentsPath,
...@@ -83,6 +84,7 @@ export default class Clusters { ...@@ -83,6 +84,7 @@ export default class Clusters {
installHelmEndpoint: installHelmPath, installHelmEndpoint: installHelmPath,
installIngressEndpoint: installIngressPath, installIngressEndpoint: installIngressPath,
installCertManagerEndpoint: installCertManagerPath, installCertManagerEndpoint: installCertManagerPath,
installCrossplaneEndpoint: installCrossplanePath,
installRunnerEndpoint: installRunnerPath, installRunnerEndpoint: installRunnerPath,
installPrometheusEndpoint: installPrometheusPath, installPrometheusEndpoint: installPrometheusPath,
installJupyterEndpoint: installJupyterPath, installJupyterEndpoint: installJupyterPath,
...@@ -227,6 +229,7 @@ export default class Clusters { ...@@ -227,6 +229,7 @@ export default class Clusters {
eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data)); eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data));
eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data)); eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data));
eventHub.$on('uninstallApplication', data => this.uninstallApplication(data)); eventHub.$on('uninstallApplication', data => this.uninstallApplication(data));
eventHub.$on('setCrossplaneProviderStack', data => this.setCrossplaneProviderStack(data));
// Add event listener to all the banner close buttons // Add event listener to all the banner close buttons
this.addBannerCloseHandler(this.unreachableContainer, 'unreachable'); this.addBannerCloseHandler(this.unreachableContainer, 'unreachable');
this.addBannerCloseHandler(this.authenticationFailureContainer, 'authentication_failure'); this.addBannerCloseHandler(this.authenticationFailureContainer, 'authentication_failure');
...@@ -238,6 +241,7 @@ export default class Clusters { ...@@ -238,6 +241,7 @@ export default class Clusters {
eventHub.$off('updateApplication', this.updateApplication); eventHub.$off('updateApplication', this.updateApplication);
eventHub.$off('saveKnativeDomain'); eventHub.$off('saveKnativeDomain');
eventHub.$off('setKnativeHostname'); eventHub.$off('setKnativeHostname');
eventHub.$off('setCrossplaneProviderStack');
eventHub.$off('uninstallApplication'); eventHub.$off('uninstallApplication');
} }
...@@ -404,18 +408,33 @@ export default class Clusters { ...@@ -404,18 +408,33 @@ export default class Clusters {
} }
installApplication({ id: appId, params }) { installApplication({ id: appId, params }) {
this.store.updateAppProperty(appId, 'requestReason', null); return Clusters.validateInstallation(appId, params)
this.store.updateAppProperty(appId, 'statusReason', null); .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(() => { resolve();
this.store.notifyInstallFailure(appId);
this.store.updateAppProperty(
appId,
'requestReason',
s__('ClusterIntegration|Request to begin installing failed'),
);
}); });
} }
...@@ -463,6 +482,12 @@ export default class Clusters { ...@@ -463,6 +482,12 @@ export default class Clusters {
this.store.updateAppProperty(appId, 'hostname', data.hostname); 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() { destroy() {
this.destroyed = true; this.destroyed = true;
... ...
......
...@@ -9,6 +9,7 @@ import jeagerLogo from 'images/cluster_app_logos/jeager.png'; ...@@ -9,6 +9,7 @@ import jeagerLogo from 'images/cluster_app_logos/jeager.png';
import jupyterhubLogo from 'images/cluster_app_logos/jupyterhub.png'; import jupyterhubLogo from 'images/cluster_app_logos/jupyterhub.png';
import kubernetesLogo from 'images/cluster_app_logos/kubernetes.png'; import kubernetesLogo from 'images/cluster_app_logos/kubernetes.png';
import certManagerLogo from 'images/cluster_app_logos/cert_manager.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 knativeLogo from 'images/cluster_app_logos/knative.png';
import meltanoLogo from 'images/cluster_app_logos/meltano.png'; import meltanoLogo from 'images/cluster_app_logos/meltano.png';
import prometheusLogo from 'images/cluster_app_logos/prometheus.png'; import prometheusLogo from 'images/cluster_app_logos/prometheus.png';
...@@ -20,6 +21,7 @@ import KnativeDomainEditor from './knative_domain_editor.vue'; ...@@ -20,6 +21,7 @@ import KnativeDomainEditor from './knative_domain_editor.vue';
import { CLUSTER_TYPE, PROVIDER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants'; import { CLUSTER_TYPE, PROVIDER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants';
import LoadingButton from '~/vue_shared/components/loading_button.vue'; import LoadingButton from '~/vue_shared/components/loading_button.vue';
import eventHub from '~/clusters/event_hub'; import eventHub from '~/clusters/event_hub';
import CrossplaneProviderStack from './crossplane_provider_stack.vue';
export default { export default {
components: { components: {
...@@ -28,6 +30,7 @@ export default { ...@@ -28,6 +30,7 @@ export default {
LoadingButton, LoadingButton,
GlLoadingIcon, GlLoadingIcon,
KnativeDomainEditor, KnativeDomainEditor,
CrossplaneProviderStack,
}, },
props: { props: {
type: { type: {
...@@ -89,6 +92,7 @@ export default { ...@@ -89,6 +92,7 @@ export default {
jupyterhubLogo, jupyterhubLogo,
kubernetesLogo, kubernetesLogo,
certManagerLogo, certManagerLogo,
crossplaneLogo,
knativeLogo, knativeLogo,
meltanoLogo, meltanoLogo,
prometheusLogo, prometheusLogo,
...@@ -116,6 +120,12 @@ export default { ...@@ -116,6 +120,12 @@ export default {
certManagerInstalled() { certManagerInstalled() {
return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED; 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() { enableClusterApplicationElasticStack() {
return gon.features && gon.features.enableClusterApplicationElasticStack; return gon.features && gon.features.enableClusterApplicationElasticStack;
}, },
...@@ -151,6 +161,24 @@ export default { ...@@ -151,6 +161,24 @@ export default {
false, 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() { prometheusDescription() {
return sprintf( return sprintf(
_.escape( _.escape(
...@@ -182,6 +210,9 @@ export default { ...@@ -182,6 +210,9 @@ export default {
knative() { knative() {
return this.applications.knative; return this.applications.knative;
}, },
crossplane() {
return this.applications.crossplane;
},
cloudRun() { cloudRun() {
return this.providerType === PROVIDER_TYPE.GCP && this.preInstalledKnative; return this.providerType === PROVIDER_TYPE.GCP && this.preInstalledKnative;
}, },
...@@ -218,6 +249,12 @@ export default { ...@@ -218,6 +249,12 @@ export default {
hostname, hostname,
}); });
}, },
setCrossplaneProviderStack(stack) {
eventHub.$emit('setCrossplaneProviderStack', {
id: 'crossplane',
stack,
});
},
}, },
}; };
</script> </script>
...@@ -228,7 +265,7 @@ export default { ...@@ -228,7 +265,7 @@ export default {
<p class="append-bottom-0"> <p class="append-bottom-0">
{{ {{
s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster. 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> <a :href="helpPath">{{ __('More information') }}</a>
</p> </p>
...@@ -253,9 +290,9 @@ export default { ...@@ -253,9 +290,9 @@ export default {
<div slot="description"> <div slot="description">
{{ {{
s__(`ClusterIntegration|Helm streamlines installing s__(`ClusterIntegration|Helm streamlines installing
and managing Kubernetes applications. and managing Kubernetes applications.
Tiller runs inside of your Kubernetes Cluster, Tiller runs inside of your Kubernetes Cluster,
and manages releases of your charts.`) and manages releases of your charts.`)
}} }}
</div> </div>
</application-row> </application-row>
...@@ -263,7 +300,7 @@ export default { ...@@ -263,7 +300,7 @@ export default {
<div class="svg-container" v-html="helmInstallIllustration"></div> <div class="svg-container" v-html="helmInstallIllustration"></div>
{{ {{
s__(`ClusterIntegration|You must first install Helm Tiller before s__(`ClusterIntegration|You must first install Helm Tiller before
installing the applications below`) installing the applications below`)
}} }}
</div> </div>
<application-row <application-row
...@@ -286,8 +323,8 @@ export default { ...@@ -286,8 +323,8 @@ export default {
<p> <p>
{{ {{
s__(`ClusterIntegration|Ingress gives you a way to route s__(`ClusterIntegration|Ingress gives you a way to route
requests to services based on the request host or path, requests to services based on the request host or path,
centralizing a number of services into a single entrypoint.`) centralizing a number of services into a single entrypoint.`)
}} }}
</p> </p>
...@@ -319,8 +356,8 @@ export default { ...@@ -319,8 +356,8 @@ export default {
<p class="form-text text-muted"> <p class="form-text text-muted">
{{ {{
s__(`ClusterIntegration|Point a wildcard DNS to this s__(`ClusterIntegration|Point a wildcard DNS to this
generated endpoint in order to access generated endpoint in order to access
your application after it has been deployed.`) your application after it has been deployed.`)
}} }}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }} {{ __('More information') }}
...@@ -331,8 +368,8 @@ export default { ...@@ -331,8 +368,8 @@ export default {
<p v-if="!ingressExternalEndpoint" class="settings-message js-no-endpoint-message"> <p v-if="!ingressExternalEndpoint" class="settings-message js-no-endpoint-message">
{{ {{
s__(`ClusterIntegration|The endpoint is in s__(`ClusterIntegration|The endpoint is in
the process of being assigned. Please check your Kubernetes the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}} }}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }} {{ __('More information') }}
...@@ -379,7 +416,7 @@ export default { ...@@ -379,7 +416,7 @@ export default {
<p class="form-text text-muted"> <p class="form-text text-muted">
{{ {{
s__(`ClusterIntegration|Issuers represent a certificate authority. 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 <a
href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email" href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email"
...@@ -435,12 +472,40 @@ export default { ...@@ -435,12 +472,40 @@ export default {
<div slot="description"> <div slot="description">
{{ {{
s__(`ClusterIntegration|GitLab Runner connects to the s__(`ClusterIntegration|GitLab Runner connects to the
repository and executes CI/CD jobs, repository and executes CI/CD jobs,
pushing results back and deploying pushing results back and deploying
applications to production.`) applications to production.`)
}} }}
</div> </div>
</application-row> </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 <application-row
id="jupyter" id="jupyter"
:logo-url="jupyterhubLogo" :logo-url="jupyterhubLogo"
...@@ -462,10 +527,10 @@ export default { ...@@ -462,10 +527,10 @@ export default {
<p> <p>
{{ {{
s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns, s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns,
manages, and proxies multiple instances of the single-user manages, and proxies multiple instances of the single-user
Jupyter notebook server. JupyterHub can be used to serve Jupyter notebook server. JupyterHub can be used to serve
notebooks to a class of students, a corporate data science group, notebooks to a class of students, a corporate data science group,
or a scientific research group.`) or a scientific research group.`)
}} }}
</p> </p>
...@@ -492,7 +557,7 @@ export default { ...@@ -492,7 +557,7 @@ export default {
<p v-if="ingressInstalled" class="form-text text-muted"> <p v-if="ingressInstalled" class="form-text text-muted">
{{ {{
s__(`ClusterIntegration|Replace this with your own hostname if you want. 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"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }} {{ __('More information') }}
...@@ -538,9 +603,9 @@ export default { ...@@ -538,9 +603,9 @@ export default {
<p> <p>
{{ {{
s__(`ClusterIntegration|Knative extends Kubernetes to provide s__(`ClusterIntegration|Knative extends Kubernetes to provide
a set of middleware components that are essential to build modern, a set of middleware components that are essential to build modern,
source-centric, and container-based applications that can run source-centric, and container-based applications that can run
anywhere: on premises, in the cloud, or even in a third-party data center.`) anywhere: on premises, in the cloud, or even in a third-party data center.`)
}} }}
</p> </p>
...@@ -612,7 +677,7 @@ export default { ...@@ -612,7 +677,7 @@ export default {
<p v-if="ingressInstalled" class="form-text text-muted"> <p v-if="ingressInstalled" class="form-text text-muted">
{{ {{
s__(`ClusterIntegration|Replace this with your own hostname if you want. 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"> <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }} {{ __('More information') }}
... ...
......
<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>
...@@ -50,6 +50,7 @@ export const JUPYTER = 'jupyter'; ...@@ -50,6 +50,7 @@ export const JUPYTER = 'jupyter';
export const KNATIVE = 'knative'; export const KNATIVE = 'knative';
export const RUNNER = 'runner'; export const RUNNER = 'runner';
export const CERT_MANAGER = 'cert_manager'; export const CERT_MANAGER = 'cert_manager';
export const CROSSPLANE = 'crossplane';
export const PROMETHEUS = 'prometheus'; export const PROMETHEUS = 'prometheus';
export const ELASTIC_STACK = 'elastic_stack'; export const ELASTIC_STACK = 'elastic_stack';
... ...
......
...@@ -7,6 +7,7 @@ export default class ClusterService { ...@@ -7,6 +7,7 @@ export default class ClusterService {
helm: this.options.installHelmEndpoint, helm: this.options.installHelmEndpoint,
ingress: this.options.installIngressEndpoint, ingress: this.options.installIngressEndpoint,
cert_manager: this.options.installCertManagerEndpoint, cert_manager: this.options.installCertManagerEndpoint,
crossplane: this.options.installCrossplaneEndpoint,
runner: this.options.installRunnerEndpoint, runner: this.options.installRunnerEndpoint,
prometheus: this.options.installPrometheusEndpoint, prometheus: this.options.installPrometheusEndpoint,
jupyter: this.options.installJupyterEndpoint, jupyter: this.options.installJupyterEndpoint,
... ...
......
...@@ -6,6 +6,7 @@ import { ...@@ -6,6 +6,7 @@ import {
KNATIVE, KNATIVE,
CERT_MANAGER, CERT_MANAGER,
ELASTIC_STACK, ELASTIC_STACK,
CROSSPLANE,
RUNNER, RUNNER,
APPLICATION_INSTALLED_STATUSES, APPLICATION_INSTALLED_STATUSES,
APPLICATION_STATUS, APPLICATION_STATUS,
...@@ -26,6 +27,7 @@ const applicationInitialState = { ...@@ -26,6 +27,7 @@ const applicationInitialState = {
uninstallable: false, uninstallable: false,
uninstallFailed: false, uninstallFailed: false,
uninstallSuccessful: false, uninstallSuccessful: false,
validationError: null,
}; };
export default class ClusterStore { export default class ClusterStore {
...@@ -58,6 +60,11 @@ export default class ClusterStore { ...@@ -58,6 +60,11 @@ export default class ClusterStore {
title: s__('ClusterIntegration|Cert-Manager'), title: s__('ClusterIntegration|Cert-Manager'),
email: null, email: null,
}, },
crossplane: {
...applicationInitialState,
title: s__('ClusterIntegration|Crossplane'),
stack: null,
},
runner: { runner: {
...applicationInitialState, ...applicationInitialState,
title: s__('ClusterIntegration|GitLab Runner'), title: s__('ClusterIntegration|GitLab Runner'),
...@@ -203,6 +210,9 @@ export default class ClusterStore { ...@@ -203,6 +210,9 @@ export default class ClusterStore {
} else if (appId === CERT_MANAGER) { } else if (appId === CERT_MANAGER) {
this.state.applications.cert_manager.email = this.state.applications.cert_manager.email =
this.state.applications.cert_manager.email || serverAppEntry.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) { } else if (appId === JUPYTER) {
this.state.applications.jupyter.hostname = this.updateHostnameIfUnset( this.state.applications.jupyter.hostname = this.updateHostnameIfUnset(
this.state.applications.jupyter.hostname, this.state.applications.jupyter.hostname,
... ...
......
...@@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController ...@@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController
end end
def cluster_application_params def cluster_application_params
params.permit(:application, :hostname, :kibana_hostname, :email) params.permit(:application, :hostname, :kibana_hostname, :email, :stack)
end end
def cluster_application_destroy_params def cluster_application_destroy_params
... ...
......
...@@ -17,6 +17,7 @@ class Clusters::ClustersController < Clusters::BaseController ...@@ -17,6 +17,7 @@ class Clusters::ClustersController < Clusters::BaseController
end end
before_action only: [:show] do before_action only: [:show] do
push_frontend_feature_flag(:enable_cluster_application_elastic_stack) push_frontend_feature_flag(:enable_cluster_application_elastic_stack)
push_frontend_feature_flag(:enable_cluster_application_crossplane)
end end
helper_method :token_in_session helper_method :token_in_session
... ...
......
# 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
...@@ -14,6 +14,7 @@ module Clusters ...@@ -14,6 +14,7 @@ module Clusters
Applications::Helm.application_name => Applications::Helm, Applications::Helm.application_name => Applications::Helm,
Applications::Ingress.application_name => Applications::Ingress, Applications::Ingress.application_name => Applications::Ingress,
Applications::CertManager.application_name => Applications::CertManager, Applications::CertManager.application_name => Applications::CertManager,
Applications::Crossplane.application_name => Applications::Crossplane,
Applications::Prometheus.application_name => Applications::Prometheus, Applications::Prometheus.application_name => Applications::Prometheus,
Applications::Runner.application_name => Applications::Runner, Applications::Runner.application_name => Applications::Runner,
Applications::Jupyter.application_name => Applications::Jupyter, Applications::Jupyter.application_name => Applications::Jupyter,
...@@ -47,6 +48,7 @@ module Clusters ...@@ -47,6 +48,7 @@ module Clusters
has_one_cluster_application :helm has_one_cluster_application :helm
has_one_cluster_application :ingress has_one_cluster_application :ingress
has_one_cluster_application :cert_manager has_one_cluster_application :cert_manager
has_one_cluster_application :crossplane
has_one_cluster_application :prometheus has_one_cluster_application :prometheus
has_one_cluster_application :runner has_one_cluster_application :runner
has_one_cluster_application :jupyter has_one_cluster_application :jupyter
... ...
......
...@@ -10,6 +10,7 @@ class ClusterApplicationEntity < Grape::Entity ...@@ -10,6 +10,7 @@ class ClusterApplicationEntity < Grape::Entity
expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) } expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) }
expose :kibana_hostname, if: -> (e, _) { e.respond_to?(:kibana_hostname) } expose :kibana_hostname, if: -> (e, _) { e.respond_to?(:kibana_hostname) }
expose :email, if: -> (e, _) { e.respond_to?(:email) } 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 :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) }
expose :can_uninstall?, as: :can_uninstall expose :can_uninstall?, as: :can_uninstall
end end
...@@ -27,6 +27,10 @@ module Clusters ...@@ -27,6 +27,10 @@ module Clusters
application.email = params[:email] application.email = params[:email]
end end
if application.has_attribute?(:stack)
application.stack = params[:stack]
end
if application.respond_to?(:oauth_application) if application.respond_to?(:oauth_application)
application.oauth_application = create_oauth_application(application, request) application.oauth_application = create_oauth_application(application, request)
end end
...@@ -64,7 +68,7 @@ module Clusters ...@@ -64,7 +68,7 @@ module Clusters
end end
def invalid_application? 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 end
def unknown_application? def unknown_application?
... ...
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
install_helm_path: clusterable.install_applications_cluster_path(@cluster, :helm), install_helm_path: clusterable.install_applications_cluster_path(@cluster, :helm),
install_ingress_path: clusterable.install_applications_cluster_path(@cluster, :ingress), install_ingress_path: clusterable.install_applications_cluster_path(@cluster, :ingress),
install_cert_manager_path: clusterable.install_applications_cluster_path(@cluster, :cert_manager), 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_prometheus_path: clusterable.install_applications_cluster_path(@cluster, :prometheus),
install_runner_path: clusterable.install_applications_cluster_path(@cluster, :runner), install_runner_path: clusterable.install_applications_cluster_path(@cluster, :runner),
install_jupyter_path: clusterable.install_applications_cluster_path(@cluster, :jupyter), install_jupyter_path: clusterable.install_applications_cluster_path(@cluster, :jupyter),
... ...
......
---
title: Support for Crossplane as a managed app
merge_request: 18797
author: Mahendra Bagul
type: added
# 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
...@@ -1078,6 +1078,17 @@ ActiveRecord::Schema.define(version: 2019_11_14_173624) do ...@@ -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 t.index ["cluster_id"], name: "index_clusters_applications_cert_managers_on_cluster_id", unique: true
end 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| create_table "clusters_applications_elastic_stacks", force: :cascade do |t|
t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false t.datetime_with_timezone "updated_at", null: false
...@@ -4222,6 +4233,7 @@ ActiveRecord::Schema.define(version: 2019_11_14_173624) do ...@@ -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", "projects", column: "management_project_id", name: "fk_f05c5e5a42", on_delete: :nullify
add_foreign_key "clusters", "users", 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_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_elastic_stacks", "clusters", on_delete: :cascade
add_foreign_key "clusters_applications_helm", "clusters", on_delete: :cascade add_foreign_key "clusters_applications_helm", "clusters", on_delete: :cascade
add_foreign_key "clusters_applications_ingress", "clusters", on_delete: :cascade add_foreign_key "clusters_applications_ingress", "clusters", on_delete: :cascade
... ...
......
...@@ -305,7 +305,7 @@ The following documentation relates to the DevOps **Configure** stage: ...@@ -305,7 +305,7 @@ The following documentation relates to the DevOps **Configure** stage:
| Configure Topics | Description | | Configure Topics | Description |
|:-----------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------| |:-----------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------|
| [Auto DevOps](topics/autodevops/index.md) | Automatically employ a complete DevOps lifecycle. | | [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. | | [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. | | [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. | | [Installing Applications](user/project/clusters/index.md#installing-applications) | Deploy Helm, Ingress, and Prometheus on Kubernetes. |
... ...
......
...@@ -100,7 +100,7 @@ To make full use of Auto DevOps, you will need: ...@@ -100,7 +100,7 @@ To make full use of Auto DevOps, you will need:
To enable deployments, 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 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 1. NGINX Ingress. You can deploy it to your Kubernetes cluster by installing
the [GitLab-managed app for Ingress](../../user/clusters/applications.md#ingress), the [GitLab-managed app for Ingress](../../user/clusters/applications.md#ingress),
once you have configured GitLab's Kubernetes integration in the previous step. once you have configured GitLab's Kubernetes integration in the previous step.
... ...
......
...@@ -5,9 +5,6 @@ GitLab can integrate with the following Kubernetes providers: ...@@ -5,9 +5,6 @@ GitLab can integrate with the following Kubernetes providers:
- Google Kubernetes Engine (GKE). - Google Kubernetes Engine (GKE).
- Amazon Elastic Kubernetes Service (EKS). - 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:** TIP: **Tip:**
Every new Google Cloud Platform (GCP) account receives [$300 in credit upon sign up](https://console.cloud.google.com/freetrial), 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 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: ...@@ -62,17 +59,17 @@ Note the following about access controls:
GitLab creates the following resources for RBAC clusters. GitLab creates the following resources for RBAC clusters.
| Name | Type | Details | Created when | | Name | Type | Details | Created when |
|:----------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:---------------------------| |:----------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:-----------------------|
| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster | | `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 GKE 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 GKE Cluster | | `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new cluster |
| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | | `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | 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 | `Namespace` | Contains all environment-specific resources | Deploying to a cluster |
| Environment namespace | `ServiceAccount` | Uses namespace of environment | 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 | `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 | | Environment namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster |
### ABAC cluster resources ### ABAC cluster resources
...@@ -80,13 +77,13 @@ GitLab creates the following resources for ABAC clusters. ...@@ -80,13 +77,13 @@ GitLab creates the following resources for ABAC clusters.
| Name | Type | Details | Created when | | Name | Type | Details | Created when |
|:----------------------|:---------------------|:-------------------------------------|:---------------------------| |:----------------------|:---------------------|:-------------------------------------|:---------------------------|
| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster | | `gitlab` | `ServiceAccount` | `default` namespace | Creating a new cluster |
| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster | | `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new cluster |
| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller | | `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | 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 | `Namespace` | Contains all environment-specific resources | Deploying to a cluster |
| Environment namespace | `ServiceAccount` | Uses namespace of environment | 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 | `Secret` | Token for environment ServiceAccount | Deploying to a cluster |
### Security of GitLab Runners ### Security of GitLab Runners
...@@ -112,7 +109,9 @@ If you don't want to use GitLab Runner in privileged mode, either: ...@@ -112,7 +109,9 @@ If you don't want to use GitLab Runner in privileged mode, either:
1. Installing a Runner 1. Installing a Runner
[using `docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html). [using `docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html).
## Add new GKE cluster ## Add new cluster
### GKE cluster
GitLab supports: GitLab supports:
...@@ -126,7 +125,7 @@ The [Google authentication integration](../../../integration/google.md) must ...@@ -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 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. 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 Before creating your first cluster on Google Kubernetes Engine with GitLab's
integration, make sure the following requirements are met: integration, make sure the following requirements are met:
...@@ -151,7 +150,7 @@ order to setup an [initial service account](#access-controls). Starting from [Gi ...@@ -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 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. 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 If all of the above requirements are met, you can proceed to create and add a
new Kubernetes cluster to your project: new Kubernetes cluster to your project:
...@@ -185,7 +184,7 @@ 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 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). 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. > [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 ...@@ -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 (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. 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 ## Add existing cluster
If you have either of the following types of clusters already, you can add them to a project: If you have either of the following types of clusters already, you can add them to a project:
... ...
......