summaryrefslogtreecommitdiff
path: root/app/assets
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-11-14 00:06:24 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-11-14 00:06:24 +0000
commiteed996ac33a60d5fd8315a62fec8beaa8e907e69 (patch)
treed8077bee50b58a170ae1a950ae76e3011c78a415 /app/assets
parentb42f312df5aee0f1b832b69171e9d1cf92eb7416 (diff)
downloadgitlab-ce-eed996ac33a60d5fd8315a62fec8beaa8e907e69.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/cluster_form_dropdown.vue99
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue1
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue182
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/region_dropdown.vue63
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue2
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/constants.js7
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/index.js20
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js134
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/actions.js59
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/index.js13
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js6
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js17
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/state.js9
13 files changed, 405 insertions, 207 deletions
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/cluster_form_dropdown.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/cluster_form_dropdown.vue
index 3c6da43c4c4..e6893c14cda 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/cluster_form_dropdown.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/cluster_form_dropdown.vue
@@ -2,14 +2,19 @@
import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_search_input.vue';
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
+import { GlIcon } from '@gitlab/ui';
-const findItem = (items, valueProp, value) => items.find(item => item[valueProp] === value);
+const toArray = value => [].concat(value);
+const itemsProp = (items, prop) => items.map(item => item[prop]);
+const defaultSearchFn = (searchQuery, labelProp) => item =>
+ item[labelProp].toLowerCase().indexOf(searchQuery) > -1;
export default {
components: {
DropdownButton,
DropdownSearchInput,
DropdownHiddenInput,
+ GlIcon,
},
props: {
fieldName: {
@@ -28,7 +33,7 @@ export default {
default: '',
},
value: {
- type: [Object, String],
+ type: [Object, Array, String],
required: false,
default: () => null,
},
@@ -72,6 +77,11 @@ export default {
required: false,
default: false,
},
+ multiple: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
errorMessage: {
type: String,
required: false,
@@ -90,12 +100,11 @@ export default {
searchFn: {
type: Function,
required: false,
- default: searchQuery => item => item.name.toLowerCase().indexOf(searchQuery) > -1,
+ default: defaultSearchFn,
},
},
data() {
return {
- selectedItem: findItem(this.items, this.value),
searchQuery: '',
};
},
@@ -109,36 +118,52 @@ export default {
return this.disabledText;
}
- if (!this.selectedItem) {
+ if (!this.selectedItems.length) {
return this.placeholder;
}
- return this.selectedItemLabel;
+ return this.selectedItemsLabels;
},
results() {
- if (!this.items) {
- return [];
- }
-
- return this.items.filter(this.searchFn(this.searchQuery));
+ return this.getItemsOrEmptyList().filter(this.searchFn(this.searchQuery, this.labelProperty));
},
- selectedItemLabel() {
- return this.selectedItem && this.selectedItem[this.labelProperty];
+ selectedItems() {
+ const valueProp = this.valueProperty;
+ const valueList = toArray(this.value);
+ const items = this.getItemsOrEmptyList();
+
+ return items.filter(item => valueList.some(value => item[valueProp] === value));
},
- selectedItemValue() {
- return (this.selectedItem && this.selectedItem[this.valueProperty]) || '';
+ selectedItemsLabels() {
+ return itemsProp(this.selectedItems, this.labelProperty).join(', ');
},
- },
- watch: {
- value(value) {
- this.selectedItem = findItem(this.items, this.valueProperty, value);
+ selectedItemsValues() {
+ return itemsProp(this.selectedItems, this.valueProperty).join(', ');
},
},
methods: {
- select(item) {
- this.selectedItem = item;
+ getItemsOrEmptyList() {
+ return this.items || [];
+ },
+ selectSingle(item) {
this.$emit('input', item[this.valueProperty]);
},
+ selectMultiple(item) {
+ const value = toArray(this.value);
+ const itemValue = item[this.valueProperty];
+ const itemValueIndex = value.indexOf(itemValue);
+
+ if (itemValueIndex > -1) {
+ value.splice(itemValueIndex, 1);
+ } else {
+ value.push(itemValue);
+ }
+
+ this.$emit('input', value);
+ },
+ isSelected(item) {
+ return this.selectedItems.includes(item);
+ },
},
};
</script>
@@ -146,7 +171,7 @@ export default {
<template>
<div>
<div class="js-gcp-machine-type-dropdown dropdown">
- <dropdown-hidden-input :name="fieldName" :value="selectedItemValue" />
+ <dropdown-hidden-input :name="fieldName" :value="selectedItemsValues" />
<dropdown-button
:class="{ 'border-danger': hasErrors }"
:is-disabled="disabled"
@@ -158,15 +183,28 @@ export default {
<div class="dropdown-content">
<ul>
<li v-if="!results.length">
- <span class="js-empty-text menu-item">
- {{ emptyText }}
- </span>
+ <span class="js-empty-text menu-item">{{ emptyText }}</span>
</li>
<li v-for="item in results" :key="item.id">
- <button class="js-dropdown-item" type="button" @click.prevent="select(item)">
- <slot name="item" :item="item">
- {{ item.name }}
- </slot>
+ <button
+ v-if="multiple"
+ class="js-dropdown-item d-flex align-items-center"
+ type="button"
+ @click.stop.prevent="selectMultiple(item)"
+ >
+ <gl-icon
+ :class="[{ invisible: !isSelected(item) }, 'mr-1']"
+ name="mobile-issue-close"
+ />
+ <slot name="item" :item="item">{{ item.name }}</slot>
+ </button>
+ <button
+ v-else
+ class="js-dropdown-item"
+ type="button"
+ @click.prevent="selectSingle(item)"
+ >
+ <slot name="item" :item="item">{{ item.name }}</slot>
</button>
</li>
</ul>
@@ -182,8 +220,7 @@ export default {
'text-muted': !hasErrors,
},
]"
+ >{{ errorMessage }}</span
>
- {{ errorMessage }}
- </span>
</div>
</template>
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue
index 6bcae6ab536..3f7c2204b9f 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue
@@ -41,6 +41,7 @@ export default {
v-if="hasCredentials"
:gitlab-managed-cluster-help-path="gitlabManagedClusterHelpPath"
:kubernetes-integration-help-path="kubernetesIntegrationHelpPath"
+ :external-link-icon="externalLinkIcon"
/>
<service-credentials-form
v-else
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
index 1188cf08850..57d5f4f541b 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
@@ -4,8 +4,8 @@ import { sprintf, s__ } from '~/locale';
import _ from 'underscore';
import { GlFormInput, GlFormCheckbox } from '@gitlab/ui';
import ClusterFormDropdown from './cluster_form_dropdown.vue';
-import RegionDropdown from './region_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(
@@ -22,13 +22,17 @@ const {
mapState: mapSecurityGroupsState,
mapActions: mapSecurityGroupsActions,
} = createNamespacedHelpers('securityGroups');
+const {
+ mapState: mapInstanceTypesState,
+ mapActions: mapInstanceTypesActions,
+} = createNamespacedHelpers('instanceTypes');
export default {
components: {
ClusterFormDropdown,
- RegionDropdown,
GlFormInput,
GlFormCheckbox,
+ LoadingButton,
},
props: {
gitlabManagedClusterHelpPath: {
@@ -39,6 +43,10 @@ export default {
type: String,
required: true,
},
+ externalLinkIcon: {
+ type: String,
+ required: true,
+ },
},
computed: {
...mapState([
@@ -51,7 +59,10 @@ export default {
'selectedSubnet',
'selectedRole',
'selectedSecurityGroup',
+ 'selectedInstanceType',
+ 'nodeCount',
'gitlabManagedCluster',
+ 'isCreatingCluster',
]),
...mapRolesState({
roles: 'items',
@@ -83,6 +94,11 @@ export default {
isLoadingSecurityGroups: 'isLoadingItems',
loadingSecurityGroupsError: 'loadingItemsError',
}),
+ ...mapInstanceTypesState({
+ instanceTypes: 'items',
+ isLoadingInstanceTypes: 'isLoadingItems',
+ loadingInstanceTypesError: 'loadingItemsError',
+ }),
kubernetesVersions() {
return KUBERNETES_VERSIONS;
},
@@ -98,6 +114,27 @@ export default {
securityGroupDropdownDisabled() {
return !this.selectedVpc;
},
+ createClusterButtonDisabled() {
+ return (
+ !this.clusterName ||
+ !this.environmentScope ||
+ !this.kubernetesVersion ||
+ !this.selectedRegion ||
+ !this.selectedKeyPair ||
+ !this.selectedVpc ||
+ !this.selectedSubnet ||
+ !this.selectedRole ||
+ !this.selectedSecurityGroup ||
+ !this.selectedInstanceType ||
+ !this.nodeCount ||
+ this.isCreatingCluster
+ );
+ },
+ createClusterButtonLabel() {
+ return this.isCreatingCluster
+ ? s__('ClusterIntegration|Creating Kubernetes cluster')
+ : s__('ClusterIntegration|Create Kubernetes cluster');
+ },
kubernetesIntegrationHelpText() {
const escapedUrl = _.escape(this.kubernetesIntegrationHelpPath);
@@ -115,11 +152,26 @@ export default {
roleDropdownHelpText() {
return sprintf(
s__(
- 'ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}.',
+ 'ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, 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#role-create" 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://console.aws.amazon.com/iam/home?#roles" target="_blank" rel="noopener noreferrer">',
+ '<a href="https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/" target="_blank" rel="noopener noreferrer">',
+ externalLinkIcon: this.externalLinkIcon,
endLink: '</a>',
},
false,
@@ -128,11 +180,12 @@ export default {
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%{endLink}.',
+ '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,
@@ -141,11 +194,12 @@ export default {
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%{endLink}.',
+ '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://console.aws.amazon.com/vpc/home?#vpc" target="_blank" rel="noopener noreferrer">',
+ '<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,
@@ -154,11 +208,12 @@ export default {
subnetDropdownHelpText() {
return sprintf(
s__(
- 'ClusterIntegration|Choose the %{startLink}subnets%{endLink} in your VPC where your worker nodes will run.',
+ '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,
@@ -167,11 +222,26 @@ export default {
securityGroupDropdownHelpText() {
return sprintf(
s__(
- 'ClusterIntegration|Choose the %{startLink}security groups%{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.',
+ '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,
@@ -195,9 +265,12 @@ export default {
mounted() {
this.fetchRegions();
this.fetchRoles();
+ this.fetchInstanceTypes();
},
methods: {
...mapActions([
+ 'createCluster',
+ 'signOut',
'setClusterName',
'setEnvironmentScope',
'setKubernetesVersion',
@@ -207,6 +280,8 @@ export default {
'setRole',
'setKeyPair',
'setSecurityGroup',
+ 'setInstanceType',
+ 'setNodeCount',
'setGitlabManagedCluster',
]),
...mapRegionsActions({ fetchRegions: 'fetchItems' }),
@@ -215,15 +290,22 @@ export default {
...mapRolesActions({ fetchRoles: 'fetchItems' }),
...mapKeyPairsActions({ fetchKeyPairs: 'fetchItems' }),
...mapSecurityGroupsActions({ fetchSecurityGroups: 'fetchItems' }),
+ ...mapInstanceTypesActions({ fetchInstanceTypes: 'fetchItems' }),
setRegionAndFetchVpcsAndKeyPairs(region) {
this.setRegion({ region });
+ this.setVpc({ vpc: null });
+ this.setKeyPair({ keyPair: null });
+ this.setSubnet({ subnet: null });
+ this.setSecurityGroup({ securityGroup: null });
this.fetchVpcs({ region });
this.fetchKeyPairs({ region });
},
setVpcAndFetchSubnets(vpc) {
this.setVpc({ vpc });
- this.fetchSubnets({ vpc });
- this.fetchSecurityGroups({ vpc });
+ this.setSubnet({ subnet: null });
+ this.setSecurityGroup({ securityGroup: null });
+ this.fetchSubnets({ vpc, region: this.selectedRegion });
+ this.fetchSecurityGroups({ vpc, region: this.selectedRegion });
},
},
};
@@ -233,7 +315,12 @@ export default {
<h2>
{{ s__('ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster') }}
</h2>
- <p v-html="kubernetesIntegrationHelpText"></p>
+ <div class="mb-3" v-html="kubernetesIntegrationHelpText"></div>
+ <div class="mb-3">
+ <button class="btn btn-link js-sign-out" @click.prevent="signOut()">
+ {{ s__('ClusterIntegration|Select a different AWS role') }}
+ </button>
+ </div>
<div class="form-group">
<label class="label-bold" for="eks-cluster-name">{{
s__('ClusterIntegration|Kubernetes cluster name')
@@ -273,7 +360,7 @@ export default {
<cluster-form-dropdown
field-id="eks-role"
field-name="eks-role"
- :input="selectedRole"
+ :value="selectedRole"
:items="roles"
:loading="isLoadingRoles"
:loading-text="s__('ClusterIntegration|Loading IAM Roles')"
@@ -288,13 +375,21 @@ export default {
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Region') }}</label>
- <region-dropdown
+ <cluster-form-dropdown
+ field-id="eks-region"
+ field-name="eks-region"
:value="selectedRegion"
- :regions="regions"
- :error="loadingRegionsError"
+ :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">{{
@@ -303,7 +398,7 @@ export default {
<cluster-form-dropdown
field-id="eks-key-pair"
field-name="eks-key-pair"
- :input="selectedKeyPair"
+ :value="selectedKeyPair"
:items="keyPairs"
:disabled="keyPairDropdownDisabled"
:disabled-text="s__('ClusterIntegration|Select a region to choose a Key Pair')"
@@ -323,7 +418,7 @@ export default {
<cluster-form-dropdown
field-id="eks-vpc"
field-name="eks-vpc"
- :input="selectedVpc"
+ :value="selectedVpc"
:items="vpcs"
:loading="isLoadingVpcs"
:disabled="vpcDropdownDisabled"
@@ -339,11 +434,12 @@ export default {
<p class="form-text text-muted" v-html="vpcDropdownHelpText"></p>
</div>
<div class="form-group">
- <label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Subnet') }}</label>
+ <label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Subnets') }}</label>
<cluster-form-dropdown
field-id="eks-subnet"
field-name="eks-subnet"
- :input="selectedSubnet"
+ multiple
+ :value="selectedSubnet"
:items="subnets"
:loading="isLoadingSubnets"
:disabled="subnetDropdownDisabled"
@@ -360,12 +456,12 @@ export default {
</div>
<div class="form-group">
<label class="label-bold" for="eks-security-group">{{
- s__('ClusterIntegration|Security groups')
+ s__('ClusterIntegration|Security group')
}}</label>
<cluster-form-dropdown
field-id="eks-security-group"
field-name="eks-security-group"
- :input="selectedSecurityGroup"
+ :value="selectedSecurityGroup"
:items="securityGroups"
:loading="isLoadingSecurityGroups"
:disabled="securityGroupDropdownDisabled"
@@ -383,6 +479,39 @@ export default {
<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 })"
@@ -390,5 +519,14 @@ export default {
>
<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>
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/region_dropdown.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/region_dropdown.vue
deleted file mode 100644
index 765955305c8..00000000000
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/region_dropdown.vue
+++ /dev/null
@@ -1,63 +0,0 @@
-<script>
-import { sprintf, s__ } from '~/locale';
-
-import ClusterFormDropdown from './cluster_form_dropdown.vue';
-
-export default {
- components: {
- ClusterFormDropdown,
- },
- props: {
- regions: {
- type: Array,
- required: false,
- default: () => [],
- },
- loading: {
- type: Boolean,
- required: false,
- default: false,
- },
- error: {
- type: Object,
- required: false,
- default: null,
- },
- },
- computed: {
- hasErrors() {
- return Boolean(this.error);
- },
- helpText() {
- return sprintf(
- s__('ClusterIntegration|Learn more about %{startLink}Regions%{endLink}.'),
- {
- startLink:
- '<a href="https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/" target="_blank" rel="noopener noreferrer">',
- endLink: '</a>',
- },
- false,
- );
- },
- },
-};
-</script>
-<template>
- <div>
- <cluster-form-dropdown
- field-id="eks-region"
- field-name="eks-region"
- :items="regions"
- :loading="loading"
- :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="hasErrors"
- :error-message="s__('ClusterIntegration|Could not load regions from your AWS account')"
- v-bind="$attrs"
- v-on="$listeners"
- />
- <p class="form-text text-muted" v-html="helpText"></p>
- </div>
-</template>
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue
index 185fecba2d8..ab33e9fbc95 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue
@@ -131,7 +131,7 @@ export default {
<p class="form-text text-muted" v-html="provisionRoleArnHelpText"></p>
</div>
<loading-button
- class="js-submit-service-credentials"
+ class="js-submit-service-credentials btn-success"
type="submit"
:disabled="submitButtonDisabled"
:loading="isCreatingRole"
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/constants.js b/app/assets/javascripts/create_cluster/eks_cluster/constants.js
index 339642f991e..a850ba89818 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/constants.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/constants.js
@@ -1,7 +1,2 @@
// eslint-disable-next-line import/prefer-default-export
-export const KUBERNETES_VERSIONS = [
- { name: '1.14', value: '1.14' },
- { name: '1.13', value: '1.13' },
- { name: '1.12', value: '1.12' },
- { name: '1.11', value: '1.11' },
-];
+export const KUBERNETES_VERSIONS = [{ name: '1.14', value: '1.14' }];
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/index.js b/app/assets/javascripts/create_cluster/eks_cluster/index.js
index e634a743d1d..27f859d8972 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/index.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/index.js
@@ -12,10 +12,19 @@ export default el => {
kubernetesIntegrationHelpPath,
accountAndExternalIdsHelpPath,
createRoleArnHelpPath,
+ getRolesPath,
+ getRegionsPath,
+ getKeyPairsPath,
+ getVpcsPath,
+ getSubnetsPath,
+ getSecurityGroupsPath,
+ getInstanceTypesPath,
externalId,
accountId,
hasCredentials,
createRolePath,
+ createClusterPath,
+ signOutPath,
externalLinkIcon,
} = el.dataset;
@@ -27,6 +36,17 @@ export default el => {
externalId,
accountId,
createRolePath,
+ createClusterPath,
+ signOutPath,
+ },
+ apiPaths: {
+ getRolesPath,
+ getRegionsPath,
+ getKeyPairsPath,
+ getVpcsPath,
+ getSubnetsPath,
+ getSecurityGroupsPath,
+ getInstanceTypesPath,
},
}),
components: {
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js b/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js
index d982e4db4c1..21b87d525cf 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/services/aws_services_facade.js
@@ -1,84 +1,58 @@
-import EC2 from 'aws-sdk/clients/ec2';
-import IAM from 'aws-sdk/clients/iam';
-
-export const fetchRoles = () => {
- const iam = new IAM();
-
- return iam
- .listRoles()
- .promise()
- .then(({ Roles: roles }) => roles.map(({ RoleName: name }) => ({ name })));
-};
-
-export const fetchKeyPairs = () => {
- const ec2 = new EC2();
-
- return ec2
- .describeKeyPairs()
- .promise()
- .then(({ KeyPairs: keyPairs }) => keyPairs.map(({ RegionName: name }) => ({ name })));
-};
-
-export const fetchRegions = () => {
- const ec2 = new EC2();
-
- return ec2
- .describeRegions()
- .promise()
- .then(({ Regions: regions }) =>
- regions.map(({ RegionName: name }) => ({
- name,
- value: name,
+import axios from '~/lib/utils/axios_utils';
+
+export default apiPaths => ({
+ fetchRoles() {
+ return axios
+ .get(apiPaths.getRolesPath)
+ .then(({ data: { roles } }) =>
+ roles.map(({ role_name: name, arn: value }) => ({ name, value })),
+ );
+ },
+ fetchKeyPairs({ region }) {
+ return axios
+ .get(apiPaths.getKeyPairsPath, { params: { region } })
+ .then(({ data: { key_pairs: keyPairs } }) =>
+ keyPairs.map(({ key_name }) => ({ name: key_name, value: key_name })),
+ );
+ },
+ fetchRegions() {
+ return axios.get(apiPaths.getRegionsPath).then(({ data: { regions } }) =>
+ regions.map(({ region_name }) => ({
+ name: region_name,
+ value: region_name,
})),
);
-};
-
-export const fetchVpcs = () => {
- const ec2 = new EC2();
-
- return ec2
- .describeVpcs()
- .promise()
- .then(({ Vpcs: vpcs }) =>
- vpcs.map(({ VpcId: id }) => ({
- value: id,
- name: id,
+ },
+ fetchVpcs({ region }) {
+ return axios.get(apiPaths.getVpcsPath, { params: { region } }).then(({ data: { vpcs } }) =>
+ vpcs.map(({ vpc_id }) => ({
+ value: vpc_id,
+ name: vpc_id,
})),
);
-};
-
-export const fetchSubnets = ({ vpc }) => {
- const ec2 = new EC2();
-
- return ec2
- .describeSubnets({
- Filters: [
- {
- Name: 'vpc-id',
- Values: [vpc],
- },
- ],
- })
- .promise()
- .then(({ Subnets: subnets }) => subnets.map(({ SubnetId: id }) => ({ id, name: id })));
-};
-
-export const fetchSecurityGroups = ({ vpc }) => {
- const ec2 = new EC2();
-
- return ec2
- .describeSecurityGroups({
- Filters: [
- {
- Name: 'vpc-id',
- Values: [vpc],
- },
- ],
- })
- .promise()
- .then(({ SecurityGroups: securityGroups }) =>
- securityGroups.map(({ GroupName: name, GroupId: value }) => ({ name, value })),
- );
-};
-
-export default () => {};
+ },
+ fetchSubnets({ vpc, region }) {
+ return axios
+ .get(apiPaths.getSubnetsPath, { params: { vpc_id: vpc, region } })
+ .then(({ data: { subnets } }) =>
+ subnets.map(({ subnet_id }) => ({ name: subnet_id, value: subnet_id })),
+ );
+ },
+ fetchSecurityGroups({ vpc, region }) {
+ return axios
+ .get(apiPaths.getSecurityGroupsPath, { params: { vpc_id: vpc, region } })
+ .then(({ data: { security_groups: securityGroups } }) =>
+ securityGroups.map(({ group_name: name, group_id: value }) => ({ name, value })),
+ );
+ },
+ fetchInstanceTypes() {
+ return axios
+ .get(apiPaths.getInstanceTypesPath)
+ .then(({ data: { instance_types: instanceTypes } }) =>
+ instanceTypes.map(({ instance_type_name }) => ({
+ name: instance_type_name,
+ value: instance_type_name,
+ })),
+ );
+ },
+});
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js b/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
index 16a7547957e..72f15263a8f 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
@@ -1,5 +1,12 @@
import * as types from './mutation_types';
import axios from '~/lib/utils/axios_utils';
+import createFlash from '~/flash';
+
+const getErrorMessage = data => {
+ const errorKey = Object.keys(data)[0];
+
+ return data[errorKey][0];
+};
export const setClusterName = ({ commit }, payload) => {
commit(types.SET_CLUSTER_NAME, payload);
@@ -37,6 +44,44 @@ export const createRoleError = ({ commit }, payload) => {
commit(types.CREATE_ROLE_ERROR, payload);
};
+export const createCluster = ({ dispatch, state }) => {
+ dispatch('requestCreateCluster');
+
+ return axios
+ .post(state.createClusterPath, {
+ name: state.clusterName,
+ environment_scope: state.environmentScope,
+ managed: state.gitlabManagedCluster,
+ provider_aws_attributes: {
+ region: state.selectedRegion,
+ vpc_id: state.selectedVpc,
+ subnet_ids: state.selectedSubnet,
+ role_arn: state.selectedRole,
+ key_name: state.selectedKeyPair,
+ security_group_id: state.selectedSecurityGroup,
+ instance_type: state.selectedInstanceType,
+ num_nodes: state.nodeCount,
+ },
+ })
+ .then(({ headers: { location } }) => dispatch('createClusterSuccess', location))
+ .catch(({ response: { data } }) => {
+ dispatch('createClusterError', data);
+ });
+};
+
+export const requestCreateCluster = ({ commit }) => {
+ commit(types.REQUEST_CREATE_CLUSTER);
+};
+
+export const createClusterSuccess = (_, location) => {
+ window.location.assign(location);
+};
+
+export const createClusterError = ({ commit }, error) => {
+ commit(types.CREATE_CLUSTER_ERROR, error);
+ createFlash(getErrorMessage(error));
+};
+
export const setRegion = ({ commit }, payload) => {
commit(types.SET_REGION, payload);
};
@@ -64,3 +109,17 @@ export const setSecurityGroup = ({ commit }, payload) => {
export const setGitlabManagedCluster = ({ commit }, payload) => {
commit(types.SET_GITLAB_MANAGED_CLUSTER, payload);
};
+
+export const setInstanceType = ({ commit }, payload) => {
+ commit(types.SET_INSTANCE_TYPE, payload);
+};
+
+export const setNodeCount = ({ commit }, payload) => {
+ commit(types.SET_NODE_COUNT, payload);
+};
+
+export const signOut = ({ commit, state: { signOutPath } }) =>
+ axios
+ .delete(signOutPath)
+ .then(() => commit(types.SIGN_OUT))
+ .catch(({ response: { data } }) => createFlash(getErrorMessage(data)));
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/index.js b/app/assets/javascripts/create_cluster/eks_cluster/store/index.js
index 22cca5b816e..5982fc8a2fd 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/index.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/index.js
@@ -6,10 +6,12 @@ import state from './state';
import clusterDropdownStore from './cluster_dropdown';
-import * as awsServices from '../services/aws_services_facade';
+import awsServicesFactory from '../services/aws_services_facade';
-const createStore = ({ initialState }) =>
- new Vuex.Store({
+const createStore = ({ initialState, apiPaths }) => {
+ const awsServices = awsServicesFactory(apiPaths);
+
+ return new Vuex.Store({
actions,
getters,
mutations,
@@ -39,7 +41,12 @@ const createStore = ({ initialState }) =>
namespaced: true,
...clusterDropdownStore(awsServices.fetchSecurityGroups),
},
+ instanceTypes: {
+ namespaced: true,
+ ...clusterDropdownStore(awsServices.fetchInstanceTypes),
+ },
},
});
+};
export default createStore;
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js b/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
index 398b48d725f..f9204cc2207 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
@@ -7,7 +7,13 @@ export const SET_KEY_PAIR = 'SET_KEY_PAIR';
export const SET_SUBNET = 'SET_SUBNET';
export const SET_ROLE = 'SET_ROLE';
export const SET_SECURITY_GROUP = 'SET_SECURITY_GROUP';
+export const SET_INSTANCE_TYPE = 'SET_INSTANCE_TYPE';
+export const SET_NODE_COUNT = 'SET_NODE_COUNT';
export const SET_GITLAB_MANAGED_CLUSTER = 'SET_GITLAB_MANAGED_CLUSTER';
export const REQUEST_CREATE_ROLE = 'REQUEST_CREATE_ROLE';
export const CREATE_ROLE_SUCCESS = 'CREATE_ROLE_SUCCESS';
export const CREATE_ROLE_ERROR = 'CREATE_ROLE_ERROR';
+export const SIGN_OUT = 'SIGN_OUT';
+export const REQUEST_CREATE_CLUSTER = 'REQUEST_CREATE_CLUSTER';
+export const CREATE_CLUSTER_SUCCESS = 'CREATE_CLUSTER_SUCCESS';
+export const CREATE_CLUSTER_ERROR = 'CREATE_CLUSTER_ERROR';
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js b/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
index f7752a23574..aa04c8f7079 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
@@ -28,6 +28,12 @@ export default {
[types.SET_SECURITY_GROUP](state, { securityGroup }) {
state.selectedSecurityGroup = securityGroup;
},
+ [types.SET_INSTANCE_TYPE](state, { instanceType }) {
+ state.selectedInstanceType = instanceType;
+ },
+ [types.SET_NODE_COUNT](state, { nodeCount }) {
+ state.nodeCount = nodeCount;
+ },
[types.SET_GITLAB_MANAGED_CLUSTER](state, { gitlabManagedCluster }) {
state.gitlabManagedCluster = gitlabManagedCluster;
},
@@ -46,4 +52,15 @@ export default {
state.createRoleError = error;
state.hasCredentials = false;
},
+ [types.REQUEST_CREATE_CLUSTER](state) {
+ state.isCreatingCluster = true;
+ state.createClusterError = null;
+ },
+ [types.CREATE_CLUSTER_ERROR](state, { error }) {
+ state.isCreatingCluster = false;
+ state.createClusterError = error;
+ },
+ [types.SIGN_OUT](state) {
+ state.hasCredentials = false;
+ },
};
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/state.js b/app/assets/javascripts/create_cluster/eks_cluster/store/state.js
index b69ae5b51e5..2e3a05a9187 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/state.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/state.js
@@ -1,5 +1,7 @@
import { KUBERNETES_VERSIONS } from '../constants';
+const [{ value: kubernetesVersion }] = KUBERNETES_VERSIONS;
+
export default () => ({
createRolePath: null,
@@ -12,13 +14,18 @@ export default () => ({
clusterName: '',
environmentScope: '*',
- kubernetesVersion: [KUBERNETES_VERSIONS].value,
+ kubernetesVersion,
selectedRegion: '',
selectedRole: '',
selectedKeyPair: '',
selectedVpc: '',
selectedSubnet: '',
selectedSecurityGroup: '',
+ selectedInstanceType: 'm5.large',
+ nodeCount: '3',
+
+ isCreatingCluster: false,
+ createClusterError: false,
gitlabManagedCluster: true,
});