532 lines
19 KiB
Vue
532 lines
19 KiB
Vue
<script>
|
|
import { createNamespacedHelpers, mapState, mapActions, mapGetters } from 'vuex';
|
|
import { escape } from 'lodash';
|
|
import { GlFormInput, GlFormCheckbox } from '@gitlab/ui';
|
|
import { sprintf, s__ } from '~/locale';
|
|
import ClusterFormDropdown from '~/create_cluster/components/cluster_form_dropdown.vue';
|
|
import { KUBERNETES_VERSIONS } from '../constants';
|
|
import LoadingButton from '~/vue_shared/components/loading_button.vue';
|
|
|
|
const { mapState: mapRolesState, mapActions: mapRolesActions } = createNamespacedHelpers('roles');
|
|
const { mapState: mapRegionsState, mapActions: mapRegionsActions } = createNamespacedHelpers(
|
|
'regions',
|
|
);
|
|
const { mapState: mapKeyPairsState, mapActions: mapKeyPairsActions } = createNamespacedHelpers(
|
|
'keyPairs',
|
|
);
|
|
const { mapState: mapVpcsState, mapActions: mapVpcActions } = createNamespacedHelpers('vpcs');
|
|
const { mapState: mapSubnetsState, mapActions: mapSubnetActions } = createNamespacedHelpers(
|
|
'subnets',
|
|
);
|
|
const {
|
|
mapState: mapSecurityGroupsState,
|
|
mapActions: mapSecurityGroupsActions,
|
|
} = createNamespacedHelpers('securityGroups');
|
|
const { mapState: mapInstanceTypesState } = createNamespacedHelpers('instanceTypes');
|
|
|
|
export default {
|
|
components: {
|
|
ClusterFormDropdown,
|
|
GlFormInput,
|
|
GlFormCheckbox,
|
|
LoadingButton,
|
|
},
|
|
props: {
|
|
gitlabManagedClusterHelpPath: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
kubernetesIntegrationHelpPath: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
externalLinkIcon: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
},
|
|
computed: {
|
|
...mapState([
|
|
'clusterName',
|
|
'environmentScope',
|
|
'kubernetesVersion',
|
|
'selectedRegion',
|
|
'selectedKeyPair',
|
|
'selectedVpc',
|
|
'selectedSubnet',
|
|
'selectedRole',
|
|
'selectedSecurityGroup',
|
|
'selectedInstanceType',
|
|
'nodeCount',
|
|
'gitlabManagedCluster',
|
|
'isCreatingCluster',
|
|
]),
|
|
...mapGetters(['subnetValid']),
|
|
...mapRolesState({
|
|
roles: 'items',
|
|
isLoadingRoles: 'isLoadingItems',
|
|
loadingRolesError: 'loadingItemsError',
|
|
}),
|
|
...mapRegionsState({
|
|
regions: 'items',
|
|
isLoadingRegions: 'isLoadingItems',
|
|
loadingRegionsError: 'loadingItemsError',
|
|
}),
|
|
...mapKeyPairsState({
|
|
keyPairs: 'items',
|
|
isLoadingKeyPairs: 'isLoadingItems',
|
|
loadingKeyPairsError: 'loadingItemsError',
|
|
}),
|
|
...mapVpcsState({
|
|
vpcs: 'items',
|
|
isLoadingVpcs: 'isLoadingItems',
|
|
loadingVpcsError: 'loadingItemsError',
|
|
}),
|
|
...mapSubnetsState({
|
|
subnets: 'items',
|
|
isLoadingSubnets: 'isLoadingItems',
|
|
loadingSubnetsError: 'loadingItemsError',
|
|
}),
|
|
...mapSecurityGroupsState({
|
|
securityGroups: 'items',
|
|
isLoadingSecurityGroups: 'isLoadingItems',
|
|
loadingSecurityGroupsError: 'loadingItemsError',
|
|
}),
|
|
...mapInstanceTypesState({
|
|
instanceTypes: 'items',
|
|
isLoadingInstanceTypes: 'isLoadingItems',
|
|
loadingInstanceTypesError: 'loadingItemsError',
|
|
}),
|
|
kubernetesVersions() {
|
|
return KUBERNETES_VERSIONS;
|
|
},
|
|
vpcDropdownDisabled() {
|
|
return !this.selectedRegion;
|
|
},
|
|
keyPairDropdownDisabled() {
|
|
return !this.selectedRegion;
|
|
},
|
|
subnetDropdownDisabled() {
|
|
return !this.selectedVpc;
|
|
},
|
|
securityGroupDropdownDisabled() {
|
|
return !this.selectedVpc;
|
|
},
|
|
createClusterButtonDisabled() {
|
|
return (
|
|
!this.clusterName ||
|
|
!this.environmentScope ||
|
|
!this.kubernetesVersion ||
|
|
!this.selectedRegion ||
|
|
!this.selectedKeyPair ||
|
|
!this.selectedVpc ||
|
|
!this.subnetValid ||
|
|
!this.selectedRole ||
|
|
!this.selectedSecurityGroup ||
|
|
!this.selectedInstanceType ||
|
|
!this.nodeCount ||
|
|
this.isCreatingCluster
|
|
);
|
|
},
|
|
displaySubnetError() {
|
|
return Boolean(this.loadingSubnetsError) || this.selectedSubnet?.length === 1;
|
|
},
|
|
createClusterButtonLabel() {
|
|
return this.isCreatingCluster
|
|
? s__('ClusterIntegration|Creating Kubernetes cluster')
|
|
: s__('ClusterIntegration|Create Kubernetes cluster');
|
|
},
|
|
kubernetesIntegrationHelpText() {
|
|
const escapedUrl = escape(this.kubernetesIntegrationHelpPath);
|
|
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration.',
|
|
),
|
|
{
|
|
link_start: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
|
|
link_end: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
roleDropdownHelpText() {
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}.',
|
|
),
|
|
{
|
|
startLink:
|
|
'<a href="https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html#create-service-role" target="_blank" rel="noopener noreferrer">',
|
|
externalLinkIcon: this.externalLinkIcon,
|
|
endLink: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
regionsDropdownHelpText() {
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}.',
|
|
),
|
|
{
|
|
startLink:
|
|
'<a href="https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/" target="_blank" rel="noopener noreferrer">',
|
|
externalLinkIcon: this.externalLinkIcon,
|
|
endLink: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
keyPairDropdownHelpText() {
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}.',
|
|
),
|
|
{
|
|
startLink:
|
|
'<a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair" target="_blank" rel="noopener noreferrer">',
|
|
externalLinkIcon: this.externalLinkIcon,
|
|
endLink: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
vpcDropdownHelpText() {
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}.',
|
|
),
|
|
{
|
|
startLink:
|
|
'<a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html#vpc-create" target="_blank" rel="noopener noreferrer">',
|
|
externalLinkIcon: this.externalLinkIcon,
|
|
endLink: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
subnetDropdownHelpText() {
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run.',
|
|
),
|
|
{
|
|
startLink:
|
|
'<a href="https://console.aws.amazon.com/vpc/home?#subnets" target="_blank" rel="noopener noreferrer">',
|
|
externalLinkIcon: this.externalLinkIcon,
|
|
endLink: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
subnetValidationErrorText() {
|
|
if (this.loadingSubnetsError) {
|
|
return s__('ClusterIntegration|Could not load subnets for the selected VPC');
|
|
}
|
|
|
|
return s__('ClusterIntegration|You should select at least two subnets');
|
|
},
|
|
securityGroupDropdownHelpText() {
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.',
|
|
),
|
|
{
|
|
startLink:
|
|
'<a href="https://console.aws.amazon.com/vpc/home?#securityGroups" target="_blank" rel="noopener noreferrer">',
|
|
externalLinkIcon: this.externalLinkIcon,
|
|
endLink: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
instanceTypesDropdownHelpText() {
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}.',
|
|
),
|
|
{
|
|
startLink:
|
|
'<a href="https://aws.amazon.com/ec2/instance-types" target="_blank" rel="noopener noreferrer">',
|
|
externalLinkIcon: this.externalLinkIcon,
|
|
endLink: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
gitlabManagedHelpText() {
|
|
const escapedUrl = escape(this.gitlabManagedClusterHelpPath);
|
|
|
|
return sprintf(
|
|
s__(
|
|
'ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}',
|
|
),
|
|
{
|
|
startLink: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
|
|
endLink: '</a>',
|
|
},
|
|
false,
|
|
);
|
|
},
|
|
},
|
|
mounted() {
|
|
this.fetchRegions();
|
|
this.fetchRoles();
|
|
},
|
|
methods: {
|
|
...mapActions([
|
|
'createCluster',
|
|
'setClusterName',
|
|
'setEnvironmentScope',
|
|
'setKubernetesVersion',
|
|
'setRegion',
|
|
'setVpc',
|
|
'setSubnet',
|
|
'setRole',
|
|
'setKeyPair',
|
|
'setSecurityGroup',
|
|
'setInstanceType',
|
|
'setNodeCount',
|
|
'setGitlabManagedCluster',
|
|
]),
|
|
...mapRegionsActions({ fetchRegions: 'fetchItems' }),
|
|
...mapVpcActions({ fetchVpcs: 'fetchItems' }),
|
|
...mapSubnetActions({ fetchSubnets: 'fetchItems' }),
|
|
...mapRolesActions({ fetchRoles: 'fetchItems' }),
|
|
...mapKeyPairsActions({ fetchKeyPairs: 'fetchItems' }),
|
|
...mapSecurityGroupsActions({ fetchSecurityGroups: 'fetchItems' }),
|
|
setRegionAndFetchVpcsAndKeyPairs(region) {
|
|
this.setRegion({ region });
|
|
this.setVpc({ vpc: null });
|
|
this.setKeyPair({ keyPair: null });
|
|
this.setSubnet({ subnet: [] });
|
|
this.setSecurityGroup({ securityGroup: null });
|
|
this.fetchVpcs({ region });
|
|
this.fetchKeyPairs({ region });
|
|
},
|
|
setVpcAndFetchSubnets(vpc) {
|
|
this.setVpc({ vpc });
|
|
this.setSubnet({ subnet: [] });
|
|
this.setSecurityGroup({ securityGroup: null });
|
|
this.fetchSubnets({ vpc, region: this.selectedRegion });
|
|
this.fetchSecurityGroups({ vpc, region: this.selectedRegion });
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
<template>
|
|
<form name="eks-cluster-configuration-form">
|
|
<h4>
|
|
{{ s__('ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster') }}
|
|
</h4>
|
|
<div class="mb-3" v-html="kubernetesIntegrationHelpText"></div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-cluster-name">{{
|
|
s__('ClusterIntegration|Kubernetes cluster name')
|
|
}}</label>
|
|
<gl-form-input
|
|
id="eks-cluster-name"
|
|
:value="clusterName"
|
|
@input="setClusterName({ clusterName: $event })"
|
|
/>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-environment-scope">{{
|
|
s__('ClusterIntegration|Environment scope')
|
|
}}</label>
|
|
<gl-form-input
|
|
id="eks-environment-scope"
|
|
:value="environmentScope"
|
|
@input="setEnvironmentScope({ environmentScope: $event })"
|
|
/>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-kubernetes-version">{{
|
|
s__('ClusterIntegration|Kubernetes version')
|
|
}}</label>
|
|
<cluster-form-dropdown
|
|
field-id="eks-kubernetes-version"
|
|
field-name="eks-kubernetes-version"
|
|
:value="kubernetesVersion"
|
|
:items="kubernetesVersions"
|
|
:empty-text="s__('ClusterIntegration|Kubernetes version not found')"
|
|
@input="setKubernetesVersion({ kubernetesVersion: $event })"
|
|
/>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Service role') }}</label>
|
|
<cluster-form-dropdown
|
|
field-id="eks-role"
|
|
field-name="eks-role"
|
|
:value="selectedRole"
|
|
:items="roles"
|
|
:loading="isLoadingRoles"
|
|
:loading-text="s__('ClusterIntegration|Loading IAM Roles')"
|
|
:placeholder="s__('ClusterIntergation|Select service role')"
|
|
:search-field-placeholder="s__('ClusterIntegration|Search IAM Roles')"
|
|
:empty-text="s__('ClusterIntegration|No IAM Roles found')"
|
|
:has-errors="Boolean(loadingRolesError)"
|
|
:error-message="s__('ClusterIntegration|Could not load IAM roles')"
|
|
@input="setRole({ role: $event })"
|
|
/>
|
|
<p class="form-text text-muted" v-html="roleDropdownHelpText"></p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Region') }}</label>
|
|
<cluster-form-dropdown
|
|
field-id="eks-region"
|
|
field-name="eks-region"
|
|
:value="selectedRegion"
|
|
:items="regions"
|
|
:loading="isLoadingRegions"
|
|
:loading-text="s__('ClusterIntegration|Loading Regions')"
|
|
:placeholder="s__('ClusterIntergation|Select a region')"
|
|
:search-field-placeholder="s__('ClusterIntegration|Search regions')"
|
|
:empty-text="s__('ClusterIntegration|No region found')"
|
|
:has-errors="Boolean(loadingRegionsError)"
|
|
:error-message="s__('ClusterIntegration|Could not load regions from your AWS account')"
|
|
@input="setRegionAndFetchVpcsAndKeyPairs($event)"
|
|
/>
|
|
<p class="form-text text-muted" v-html="regionsDropdownHelpText"></p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-key-pair">{{
|
|
s__('ClusterIntegration|Key pair name')
|
|
}}</label>
|
|
<cluster-form-dropdown
|
|
field-id="eks-key-pair"
|
|
field-name="eks-key-pair"
|
|
:value="selectedKeyPair"
|
|
:items="keyPairs"
|
|
:disabled="keyPairDropdownDisabled"
|
|
:disabled-text="s__('ClusterIntegration|Select a region to choose a Key Pair')"
|
|
:loading="isLoadingKeyPairs"
|
|
:loading-text="s__('ClusterIntegration|Loading Key Pairs')"
|
|
:placeholder="s__('ClusterIntergation|Select key pair')"
|
|
:search-field-placeholder="s__('ClusterIntegration|Search Key Pairs')"
|
|
:empty-text="s__('ClusterIntegration|No Key Pairs found')"
|
|
:has-errors="Boolean(loadingKeyPairsError)"
|
|
:error-message="s__('ClusterIntegration|Could not load Key Pairs')"
|
|
@input="setKeyPair({ keyPair: $event })"
|
|
/>
|
|
<p class="form-text text-muted" v-html="keyPairDropdownHelpText"></p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-vpc">{{ s__('ClusterIntegration|VPC') }}</label>
|
|
<cluster-form-dropdown
|
|
field-id="eks-vpc"
|
|
field-name="eks-vpc"
|
|
:value="selectedVpc"
|
|
:items="vpcs"
|
|
:loading="isLoadingVpcs"
|
|
:disabled="vpcDropdownDisabled"
|
|
:disabled-text="s__('ClusterIntegration|Select a region to choose a VPC')"
|
|
:loading-text="s__('ClusterIntegration|Loading VPCs')"
|
|
:placeholder="s__('ClusterIntergation|Select a VPC')"
|
|
:search-field-placeholder="s__('ClusterIntegration|Search VPCs')"
|
|
:empty-text="s__('ClusterIntegration|No VPCs found')"
|
|
:has-errors="Boolean(loadingVpcsError)"
|
|
:error-message="s__('ClusterIntegration|Could not load VPCs for the selected region')"
|
|
@input="setVpcAndFetchSubnets($event)"
|
|
/>
|
|
<p class="form-text text-muted" v-html="vpcDropdownHelpText"></p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Subnets') }}</label>
|
|
<cluster-form-dropdown
|
|
field-id="eks-subnet"
|
|
field-name="eks-subnet"
|
|
multiple
|
|
:value="selectedSubnet"
|
|
:items="subnets"
|
|
:loading="isLoadingSubnets"
|
|
:disabled="subnetDropdownDisabled"
|
|
:disabled-text="s__('ClusterIntegration|Select a VPC to choose a subnet')"
|
|
:loading-text="s__('ClusterIntegration|Loading subnets')"
|
|
:placeholder="s__('ClusterIntergation|Select a subnet')"
|
|
:search-field-placeholder="s__('ClusterIntegration|Search subnets')"
|
|
:empty-text="s__('ClusterIntegration|No subnet found')"
|
|
:has-errors="displaySubnetError"
|
|
:error-message="subnetValidationErrorText"
|
|
@input="setSubnet({ subnet: $event })"
|
|
/>
|
|
<p class="form-text text-muted" v-html="subnetDropdownHelpText"></p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-security-group">{{
|
|
s__('ClusterIntegration|Security group')
|
|
}}</label>
|
|
<cluster-form-dropdown
|
|
field-id="eks-security-group"
|
|
field-name="eks-security-group"
|
|
:value="selectedSecurityGroup"
|
|
:items="securityGroups"
|
|
:loading="isLoadingSecurityGroups"
|
|
:disabled="securityGroupDropdownDisabled"
|
|
:disabled-text="s__('ClusterIntegration|Select a VPC to choose a security group')"
|
|
:loading-text="s__('ClusterIntegration|Loading security groups')"
|
|
:placeholder="s__('ClusterIntergation|Select a security group')"
|
|
:search-field-placeholder="s__('ClusterIntegration|Search security groups')"
|
|
:empty-text="s__('ClusterIntegration|No security group found')"
|
|
:has-errors="Boolean(loadingSecurityGroupsError)"
|
|
:error-message="
|
|
s__('ClusterIntegration|Could not load security groups for the selected VPC')
|
|
"
|
|
@input="setSecurityGroup({ securityGroup: $event })"
|
|
/>
|
|
<p class="form-text text-muted" v-html="securityGroupDropdownHelpText"></p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-instance-type">{{
|
|
s__('ClusterIntegration|Instance type')
|
|
}}</label>
|
|
<cluster-form-dropdown
|
|
field-id="eks-instance-type"
|
|
field-name="eks-instance-type"
|
|
:value="selectedInstanceType"
|
|
:items="instanceTypes"
|
|
:loading="isLoadingInstanceTypes"
|
|
:loading-text="s__('ClusterIntegration|Loading instance types')"
|
|
:placeholder="s__('ClusterIntergation|Select an instance type')"
|
|
:search-field-placeholder="s__('ClusterIntegration|Search instance types')"
|
|
:empty-text="s__('ClusterIntegration|No instance type found')"
|
|
:has-errors="Boolean(loadingInstanceTypesError)"
|
|
:error-message="s__('ClusterIntegration|Could not load instance types')"
|
|
@input="setInstanceType({ instanceType: $event })"
|
|
/>
|
|
<p class="form-text text-muted" v-html="instanceTypesDropdownHelpText"></p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="label-bold" for="eks-node-count">{{
|
|
s__('ClusterIntegration|Number of nodes')
|
|
}}</label>
|
|
<gl-form-input
|
|
id="eks-node-count"
|
|
type="number"
|
|
min="1"
|
|
step="1"
|
|
:value="nodeCount"
|
|
@input="setNodeCount({ nodeCount: $event })"
|
|
/>
|
|
</div>
|
|
<div class="form-group">
|
|
<gl-form-checkbox
|
|
:checked="gitlabManagedCluster"
|
|
@input="setGitlabManagedCluster({ gitlabManagedCluster: $event })"
|
|
>{{ s__('ClusterIntegration|GitLab-managed cluster') }}</gl-form-checkbox
|
|
>
|
|
<p class="form-text text-muted" v-html="gitlabManagedHelpText"></p>
|
|
</div>
|
|
<div class="form-group">
|
|
<loading-button
|
|
class="js-create-cluster btn-success"
|
|
:disabled="createClusterButtonDisabled"
|
|
:loading="isCreatingCluster"
|
|
:label="createClusterButtonLabel"
|
|
@click="createCluster()"
|
|
/>
|
|
</div>
|
|
</form>
|
|
</template>
|