summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Tang <dtang@gitlab.com>2018-05-23 12:16:14 +0200
committerDennis Tang <dtang@gitlab.com>2018-05-23 13:30:11 +0200
commitc960fea1814f116bd44c38a7313777fd24733a31 (patch)
tree49cca8a2d96686e172649d8806a356022114214f
parent2b903eceda1253e60fa98ba00d2fe12f6fa0d9ba (diff)
downloadgitlab-ce-c960fea1814f116bd44c38a7313777fd24733a31.tar.gz
validate project billing status after selection
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue10
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue57
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue14
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/constants.js2
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/index.js21
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/store/actions.js35
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutations.js3
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/store/state.js1
9 files changed, 111 insertions, 33 deletions
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue
index cc4d863a989..5cb1ae670dc 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue
@@ -8,14 +8,14 @@ export default {
name: 'GkeMachineTypeDropdown',
mixins: [gkeDropdownMixin],
computed: {
- ...mapState(['selectedProject', 'selectedZone', 'selectedMachineType']),
+ ...mapState(['projectHasBillingEnabled', 'selectedZone', 'selectedMachineType']),
...mapState({ items: 'machineTypes' }),
- ...mapGetters(['hasProject', 'hasZone', 'hasMachineType']),
+ ...mapGetters(['hasZone', 'hasMachineType']),
allDropdownsSelected() {
- return this.hasProject && this.hasZone && this.hasMachineType;
+ return this.projectHasBillingEnabled && this.hasZone && this.hasMachineType;
},
isDisabled() {
- return !this.selectedProject || !this.selectedZone;
+ return !this.projectHasBillingEnabled || !this.selectedZone;
},
toggleText() {
if (this.isLoading) {
@@ -26,7 +26,7 @@ export default {
return this.selectedMachineType;
}
- if (!this.hasProject && !this.hasZone) {
+ if (!this.projectHasBillingEnabled && !this.hasZone) {
return s__('ClusterIntegration|Select project and zone to choose machine type');
}
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue
index a322b7c375e..28440da635b 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue
@@ -14,8 +14,13 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ isValidatingProjectBilling: false,
+ };
+ },
computed: {
- ...mapState(['selectedProject']),
+ ...mapState(['selectedProject', 'projectHasBillingEnabled']),
...mapState({ items: 'projects' }),
...mapGetters(['hasProject']),
hasOneProject() {
@@ -25,6 +30,10 @@ export default {
return this.items && this.items.length < 2;
},
toggleText() {
+ if (this.isValidatingProjectBilling) {
+ return s__('ClusterIntegration|Validating project billing status');
+ }
+
if (this.isLoading) {
return s__('ClusterIntegration|Fetching projects');
}
@@ -42,7 +51,7 @@ export default {
helpText() {
let message;
if (this.hasErrors) {
- message = this.gapiError;
+ return this.errorMessage;
}
if (!this.items) {
@@ -67,12 +76,45 @@ export default {
);
},
errorMessage() {
+ if (!this.projectHasBillingEnabled) {
+ if (this.gapiError) {
+ return s__(
+ 'ClusterIntegration|We could not verify that one of your projects on GCP has billing enabled. Please try again.',
+ );
+ }
+
+ return sprintf(
+ s__(
+ 'Please <a href=%{linkToBilling} target="_blank" rel="noopener noreferrer">enable billing for one of your projects to be able to create a Kubernetes cluster</a>, then try again.',
+ ),
+ {
+ linkToBilling:
+ 'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral',
+ },
+ false,
+ );
+ }
+
return sprintf(
s__('ClusterIntegration|An error occured while trying to fetch your projects: %{error}'),
{ error: this.gapiError },
);
},
},
+ watch: {
+ selectedProject() {
+ this.isLoading = true;
+ this.isValidatingProjectBilling = true;
+
+ this.validateProjectBilling()
+ .then(this.validateProjectBillingSuccessHandler)
+ .catch(this.validateProjectBillingFailureHandler);
+ },
+ projectHasBillingEnabled(billingEnabled) {
+ this.hasErrors = !billingEnabled;
+ this.isValidatingProjectBilling = false;
+ },
+ },
created() {
this.isLoading = true;
@@ -81,7 +123,7 @@ export default {
.catch(this.fetchFailureHandler);
},
methods: {
- ...mapActions(['fetchProjects']),
+ ...mapActions(['fetchProjects', 'validateProjectBilling']),
...mapActions({ setItem: 'setProject' }),
fetchSuccessHandler() {
if (this.defaultValue) {
@@ -97,6 +139,15 @@ export default {
this.isLoading = false;
this.hasErrors = false;
},
+ validateProjectBillingSuccessHandler() {
+ this.isLoading = false;
+ },
+ validateProjectBillingFailureHandler(resp) {
+ this.isLoading = false;
+ this.hasErrors = true;
+
+ this.gapiError = resp.result ? resp.result.error.message : resp;
+ },
},
};
</script>
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue
index 46d84bbb751..43531813407 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue
@@ -1,6 +1,6 @@
<script>
import { sprintf, s__ } from '~/locale';
-import { mapState, mapGetters, mapActions } from 'vuex';
+import { mapState, mapActions } from 'vuex';
import gkeDropdownMixin from './gke_dropdown_mixin';
@@ -8,11 +8,10 @@ export default {
name: 'GkeZoneDropdown',
mixins: [gkeDropdownMixin],
computed: {
- ...mapState(['selectedProject', 'selectedZone', 'projects']),
+ ...mapState(['selectedProject', 'selectedZone', 'projects', 'projectHasBillingEnabled']),
...mapState({ items: 'zones' }),
- ...mapGetters(['hasProject']),
isDisabled() {
- return !this.hasProject;
+ return !this.projectHasBillingEnabled;
},
toggleText() {
if (this.isLoading) {
@@ -23,7 +22,7 @@ export default {
return this.selectedZone;
}
- return !this.hasProject
+ return !this.projectHasBillingEnabled
? s__('ClusterIntegration|Select project to choose zone')
: s__('ClusterIntegration|Select zone');
},
@@ -35,10 +34,11 @@ export default {
},
},
watch: {
- selectedProject() {
+ projectHasBillingEnabled(billingEnabled) {
+ if (!billingEnabled) return false;
this.isLoading = true;
- this.fetchZones()
+ return this.fetchZones()
.then(this.fetchSuccessHandler)
.catch(this.fetchFailureHandler);
},
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/constants.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/constants.js
index 100331df819..2a1c0819916 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/constants.js
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/constants.js
@@ -3,6 +3,8 @@ import { s__ } from '~/locale';
export const GCP_API_ERROR = s__(
'ClusterIntegration|An error occurred when trying to contact the Google Cloud API. Please try again later.',
);
+export const GCP_API_CLOUD_BILLING_ENDPOINT =
+ 'https://www.googleapis.com/discovery/v1/apis/cloudbilling/v1/rest';
export const GCP_API_CLOUD_RESOURCE_MANAGER_ENDPOINT =
'https://www.googleapis.com/discovery/v1/apis/cloudresourcemanager/v1/rest';
export const GCP_API_COMPUTE_ENDPOINT =
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/index.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/index.js
index 79255e654f2..729b9404b64 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/index.js
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/index.js
@@ -56,19 +56,20 @@ const gkeDropdownErrorHandler = () => {
const initializeGapiClient = () => {
const el = document.querySelector('.js-gke-cluster-creation');
+ if (!el) return false;
- gapi.client.setToken({ access_token: el.dataset.token });
-
- gapi.client
- .load(CONSTANTS.GCP_API_CLOUD_RESOURCE_MANAGER_ENDPOINT)
- .then(() => {
- mountGkeProjectIdDropdown();
+ return gapi.client
+ .init({
+ discoveryDocs: [
+ CONSTANTS.GCP_API_CLOUD_BILLING_ENDPOINT,
+ CONSTANTS.GCP_API_CLOUD_RESOURCE_MANAGER_ENDPOINT,
+ CONSTANTS.GCP_API_COMPUTE_ENDPOINT,
+ ],
})
- .catch(gkeDropdownErrorHandler);
-
- gapi.client
- .load(CONSTANTS.GCP_API_COMPUTE_ENDPOINT)
.then(() => {
+ gapi.client.setToken({ access_token: el.dataset.token });
+
+ mountGkeProjectIdDropdown();
mountGkeZoneDropdown();
mountGkeMachineTypeDropdown();
})
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/store/actions.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/store/actions.js
index 11bd04f5b01..409265175a4 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/store/actions.js
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/store/actions.js
@@ -1,9 +1,9 @@
/* global gapi */
import * as types from './mutation_types';
-const gapiRequest = ({ service, params, commit, mutation, payloadKey }) =>
+const gapiResourceListRequest = ({ resource, params, commit, mutation, payloadKey }) =>
new Promise((resolve, reject) => {
- const request = service.list(params);
+ const request = resource.list(params);
return request.then(
resp => {
@@ -32,17 +32,36 @@ export const setMachineType = ({ commit }, selectedMachineType) => {
};
export const fetchProjects = ({ commit }) =>
- gapiRequest({
- service: gapi.client.cloudresourcemanager.projects,
+ gapiResourceListRequest({
+ resource: gapi.client.cloudresourcemanager.projects,
params: {},
commit,
mutation: types.SET_PROJECTS,
payloadKey: 'projects',
});
+export const validateProjectBilling = ({ commit, state }) =>
+ new Promise((resolve, reject) => {
+ const request = gapi.client.cloudbilling.projects.getBillingInfo({
+ name: `projects/${state.selectedProject.projectId}`,
+ });
+
+ return request.then(
+ resp => {
+ const { billingEnabled } = resp.result;
+
+ commit(types.SET_PROJECT_BILLING_STATUS, !!billingEnabled);
+ resolve();
+ },
+ resp => {
+ reject(resp);
+ },
+ );
+ });
+
export const fetchZones = ({ commit, state }) =>
- gapiRequest({
- service: gapi.client.compute.zones,
+ gapiResourceListRequest({
+ resource: gapi.client.compute.zones,
params: {
project: state.selectedProject.projectId,
},
@@ -52,8 +71,8 @@ export const fetchZones = ({ commit, state }) =>
});
export const fetchMachineTypes = ({ commit, state }) =>
- gapiRequest({
- service: gapi.client.compute.machineTypes,
+ gapiResourceListRequest({
+ resource: gapi.client.compute.machineTypes,
params: {
project: state.selectedProject.projectId,
zone: state.selectedZone,
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutation_types.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutation_types.js
index 6577612b4cd..98574289bc4 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutation_types.js
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutation_types.js
@@ -1,4 +1,5 @@
export const SET_PROJECT = 'SET_PROJECT';
+export const SET_PROJECT_BILLING_STATUS = 'SET_PROJECT_BILLING_STATUS';
export const SET_ZONE = 'SET_ZONE';
export const SET_MACHINE_TYPE = 'SET_MACHINE_TYPE';
export const SET_PROJECTS = 'SET_PROJECTS';
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutations.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutations.js
index 95b7ed68053..a9ff3b503f4 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutations.js
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/store/mutations.js
@@ -4,6 +4,9 @@ export default {
[types.SET_PROJECT](state, selectedProject) {
Object.assign(state, { selectedProject });
},
+ [types.SET_PROJECT_BILLING_STATUS](state, projectHasBillingEnabled) {
+ Object.assign(state, { projectHasBillingEnabled });
+ },
[types.SET_ZONE](state, selectedZone) {
Object.assign(state, { selectedZone });
},
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/store/state.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/store/state.js
index 5b1ed85bdb2..5ed8a8da7b5 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/store/state.js
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/store/state.js
@@ -5,6 +5,7 @@ export default {
},
selectedZone: '',
selectedMachineType: '',
+ projectHasBillingEnabled: null,
projects: [],
zones: [],
machineTypes: [],