summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnrique Alcantara <ealcantara@gitlab.com>2019-04-23 15:08:09 -0400
committerEnrique Alcantara <ealcantara@gitlab.com>2019-04-30 10:52:33 -0400
commit4dfb9290e23da1248404af1651b670f01ff6956b (patch)
tree53800b144d85532efa5a0c055a8e6c359b94ea2b
parentb0043179da70847c20f90a6e80661764b273cc05 (diff)
downloadgitlab-ce-4dfb9290e23da1248404af1651b670f01ff6956b.tar.gz
Handle uninstall request in clusters bundle
- Handle uninstallApplication event - Transition application state machine to uninstalling when uninstallApplication event is captured. - Send DELETE request to application route to start the uninstalling process.
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js23
-rw-r--r--app/assets/javascripts/clusters/constants.js6
-rw-r--r--app/assets/javascripts/clusters/services/clusters_service.js4
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js11
-rw-r--r--spec/frontend/clusters/clusters_bundle_spec.js82
-rw-r--r--spec/frontend/clusters/services/mock_data.js7
-rw-r--r--spec/frontend/clusters/stores/clusters_store_spec.js14
7 files changed, 97 insertions, 50 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 8461e01de7b..561b6bdd9f1 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -132,6 +132,7 @@ export default class Clusters {
eventHub.$on('dismissUpgradeSuccess', appId => this.dismissUpgradeSuccess(appId));
eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data));
eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data));
+ eventHub.$on('uninstallApplication', data => this.uninstallApplication(data));
}
removeListeners() {
@@ -141,6 +142,7 @@ export default class Clusters {
eventHub.$off('dismissUpgradeSuccess', this.dismissUpgradeSuccess);
eventHub.$off('saveKnativeDomain');
eventHub.$off('setKnativeHostname');
+ eventHub.$off('uninstallApplication');
}
initPolling() {
@@ -249,14 +251,13 @@ export default class Clusters {
}
}
- installApplication(data) {
- const appId = data.id;
+ installApplication({ id: appId, params }) {
this.store.updateAppProperty(appId, 'requestReason', null);
this.store.updateAppProperty(appId, 'statusReason', null);
this.store.installApplication(appId);
- return this.service.installApplication(appId, data.params).catch(() => {
+ return this.service.installApplication(appId, params).catch(() => {
this.store.notifyInstallFailure(appId);
this.store.updateAppProperty(
appId,
@@ -266,6 +267,22 @@ export default class Clusters {
});
}
+ uninstallApplication({ id: appId }) {
+ this.store.updateAppProperty(appId, 'requestReason', null);
+ this.store.updateAppProperty(appId, 'statusReason', null);
+
+ this.store.uninstallApplication(appId);
+
+ return this.service.uninstallApplication(appId).catch(() => {
+ this.store.notifyUninstallFailure(appId);
+ this.store.updateAppProperty(
+ appId,
+ 'requestReason',
+ s__('ClusterIntegration|Request to begin uninstalling failed'),
+ );
+ });
+ }
+
upgradeApplication(data) {
const appId = data.id;
diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js
index 74fe6417fbc..8fd752092c9 100644
--- a/app/assets/javascripts/clusters/constants.js
+++ b/app/assets/javascripts/clusters/constants.js
@@ -28,17 +28,23 @@ export const APPLICATION_STATUS = {
export const APPLICATION_INSTALLED_STATUSES = [
APPLICATION_STATUS.INSTALLED,
APPLICATION_STATUS.UPDATING,
+ APPLICATION_STATUS.UNINSTALLING,
];
// These are only used client-side
export const UPDATE_EVENT = 'update';
export const INSTALL_EVENT = 'install';
+export const UNINSTALL_EVENT = 'uninstall';
+export const HELM = 'helm';
export const INGRESS = 'ingress';
export const JUPYTER = 'jupyter';
export const KNATIVE = 'knative';
export const RUNNER = 'runner';
export const CERT_MANAGER = 'cert_manager';
export const PROMETHEUS = 'prometheus';
+
+export const APPLICATIONS = [HELM, INGRESS, JUPYTER, KNATIVE, RUNNER, CERT_MANAGER, PROMETHEUS];
+
export const INGRESS_DOMAIN_SUFFIX = '.nip.io';
diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js
index dea33ac44c5..01f3732de7e 100644
--- a/app/assets/javascripts/clusters/services/clusters_service.js
+++ b/app/assets/javascripts/clusters/services/clusters_service.js
@@ -29,6 +29,10 @@ export default class ClusterService {
return axios.patch(this.appUpdateEndpointMap[appId], params);
}
+ uninstallApplication(appId, params) {
+ return axios.delete(this.appInstallEndpointMap[appId], params);
+ }
+
static updateCluster(endpoint, data) {
return axios.put(endpoint, data);
}
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index d3054f7d731..1b4d7e8372c 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -10,6 +10,7 @@ import {
APPLICATION_STATUS,
INSTALL_EVENT,
UPDATE_EVENT,
+ UNINSTALL_EVENT,
} from '../constants';
import transitionApplicationState from '../services/application_state_machine';
@@ -119,6 +120,14 @@ export default class ClusterStore {
this.handleApplicationEvent(appId, APPLICATION_STATUS.UPDATE_ERRORED);
}
+ uninstallApplication(appId) {
+ this.handleApplicationEvent(appId, UNINSTALL_EVENT);
+ }
+
+ notifyUninstallFailure(appId) {
+ this.handleApplicationEvent(appId, APPLICATION_STATUS.UNINSTALL_ERRORED);
+ }
+
handleApplicationEvent(appId, event) {
const currentAppState = this.state.applications[appId];
@@ -144,6 +153,7 @@ export default class ClusterStore {
status_reason: statusReason,
version,
update_available: upgradeAvailable,
+ can_uninstall: uninstallable,
} = serverAppEntry;
const currentApplicationState = this.state.applications[appId] || {};
const nextApplicationState = transitionApplicationState(currentApplicationState, status);
@@ -153,6 +163,7 @@ export default class ClusterStore {
...nextApplicationState,
statusReason,
installed: isApplicationInstalled(nextApplicationState.status),
+ uninstallable,
};
if (appId === INGRESS) {
diff --git a/spec/frontend/clusters/clusters_bundle_spec.js b/spec/frontend/clusters/clusters_bundle_spec.js
index a61103397eb..73897107f67 100644
--- a/spec/frontend/clusters/clusters_bundle_spec.js
+++ b/spec/frontend/clusters/clusters_bundle_spec.js
@@ -1,12 +1,12 @@
import Clusters from '~/clusters/clusters_bundle';
-import { APPLICATION_STATUS, INGRESS_DOMAIN_SUFFIX } from '~/clusters/constants';
+import { APPLICATION_STATUS, INGRESS_DOMAIN_SUFFIX, APPLICATIONS } from '~/clusters/constants';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { loadHTMLFixture } from 'helpers/fixtures';
import { setTestTimeout } from 'helpers/timeout';
import $ from 'jquery';
-const { INSTALLING, INSTALLABLE, INSTALLED } = APPLICATION_STATUS;
+const { INSTALLING, INSTALLABLE, INSTALLED, UNINSTALLING } = APPLICATION_STATUS;
describe('Clusters', () => {
setTestTimeout(1000);
@@ -212,73 +212,61 @@ describe('Clusters', () => {
});
describe('installApplication', () => {
- it('tries to install helm', () => {
+ it.each(APPLICATIONS)('tries to install %s', applicationId => {
jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce();
- cluster.store.state.applications.helm.status = INSTALLABLE;
+ cluster.store.state.applications[applicationId].status = INSTALLABLE;
- cluster.installApplication({ id: 'helm' });
+ cluster.installApplication({ id: applicationId });
- expect(cluster.store.state.applications.helm.status).toEqual(INSTALLING);
- expect(cluster.store.state.applications.helm.requestReason).toEqual(null);
- expect(cluster.service.installApplication).toHaveBeenCalledWith('helm', undefined);
+ expect(cluster.store.state.applications[applicationId].status).toEqual(INSTALLING);
+ expect(cluster.store.state.applications[applicationId].requestReason).toEqual(null);
+ expect(cluster.service.installApplication).toHaveBeenCalledWith(applicationId, undefined);
});
- it('tries to install ingress', () => {
- jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce();
-
- cluster.store.state.applications.ingress.status = INSTALLABLE;
-
- cluster.installApplication({ id: 'ingress' });
-
- expect(cluster.store.state.applications.ingress.status).toEqual(INSTALLING);
- expect(cluster.store.state.applications.ingress.requestReason).toEqual(null);
- expect(cluster.service.installApplication).toHaveBeenCalledWith('ingress', undefined);
- });
+ it('sets error request status when the request fails', () => {
+ jest
+ .spyOn(cluster.service, 'installApplication')
+ .mockRejectedValueOnce(new Error('STUBBED ERROR'));
- it('tries to install runner', () => {
- jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce();
+ cluster.store.state.applications.helm.status = INSTALLABLE;
- cluster.store.state.applications.runner.status = INSTALLABLE;
+ const promise = cluster.installApplication({ id: 'helm' });
- cluster.installApplication({ id: 'runner' });
+ return promise.then(() => {
+ expect(cluster.store.state.applications.helm.status).toEqual(INSTALLABLE);
+ expect(cluster.store.state.applications.helm.installFailed).toBe(true);
- expect(cluster.store.state.applications.runner.status).toEqual(INSTALLING);
- expect(cluster.store.state.applications.runner.requestReason).toEqual(null);
- expect(cluster.service.installApplication).toHaveBeenCalledWith('runner', undefined);
+ expect(cluster.store.state.applications.helm.requestReason).toBeDefined();
+ });
});
+ });
- it('tries to install jupyter', () => {
- jest.spyOn(cluster.service, 'installApplication').mockResolvedValueOnce();
+ describe('uninstallApplication', () => {
+ it.each(APPLICATIONS)('tries to uninstall %s', applicationId => {
+ jest.spyOn(cluster.service, 'uninstallApplication').mockResolvedValueOnce();
- cluster.installApplication({
- id: 'jupyter',
- params: { hostname: cluster.store.state.applications.jupyter.hostname },
- });
+ cluster.store.state.applications[applicationId].status = INSTALLED;
- cluster.store.state.applications.jupyter.status = INSTALLABLE;
- expect(cluster.store.state.applications.jupyter.requestReason).toEqual(null);
- expect(cluster.service.installApplication).toHaveBeenCalledWith('jupyter', {
- hostname: cluster.store.state.applications.jupyter.hostname,
- });
+ cluster.uninstallApplication({ id: applicationId });
+
+ expect(cluster.store.state.applications[applicationId].status).toEqual(UNINSTALLING);
+ expect(cluster.store.state.applications[applicationId].requestReason).toEqual(null);
+ expect(cluster.service.uninstallApplication).toHaveBeenCalledWith(applicationId);
});
- it('sets error request status when the request fails', () => {
+ it('sets error request status when the uninstall request fails', () => {
jest
- .spyOn(cluster.service, 'installApplication')
+ .spyOn(cluster.service, 'uninstallApplication')
.mockRejectedValueOnce(new Error('STUBBED ERROR'));
- cluster.store.state.applications.helm.status = INSTALLABLE;
+ cluster.store.state.applications.helm.status = INSTALLED;
- const promise = cluster.installApplication({ id: 'helm' });
-
- expect(cluster.store.state.applications.helm.status).toEqual(INSTALLING);
- expect(cluster.store.state.applications.helm.requestReason).toEqual(null);
- expect(cluster.service.installApplication).toHaveBeenCalled();
+ const promise = cluster.uninstallApplication({ id: 'helm' });
return promise.then(() => {
- expect(cluster.store.state.applications.helm.status).toEqual(INSTALLABLE);
- expect(cluster.store.state.applications.helm.installFailed).toBe(true);
+ expect(cluster.store.state.applications.helm.status).toEqual(INSTALLED);
+ expect(cluster.store.state.applications.helm.uninstallFailed).toBe(true);
expect(cluster.store.state.applications.helm.requestReason).toBeDefined();
});
diff --git a/spec/frontend/clusters/services/mock_data.js b/spec/frontend/clusters/services/mock_data.js
index 1e896af1c7d..41ad398e924 100644
--- a/spec/frontend/clusters/services/mock_data.js
+++ b/spec/frontend/clusters/services/mock_data.js
@@ -11,6 +11,7 @@ const CLUSTERS_MOCK_DATA = {
name: 'helm',
status: APPLICATION_STATUS.INSTALLABLE,
status_reason: null,
+ can_uninstall: false,
},
{
name: 'ingress',
@@ -18,32 +19,38 @@ const CLUSTERS_MOCK_DATA = {
status_reason: 'Cannot connect',
external_ip: null,
external_hostname: null,
+ can_uninstall: false,
},
{
name: 'runner',
status: APPLICATION_STATUS.INSTALLING,
status_reason: null,
+ can_uninstall: false,
},
{
name: 'prometheus',
status: APPLICATION_STATUS.ERROR,
status_reason: 'Cannot connect',
+ can_uninstall: false,
},
{
name: 'jupyter',
status: APPLICATION_STATUS.INSTALLING,
status_reason: 'Cannot connect',
+ can_uninstall: false,
},
{
name: 'knative',
status: APPLICATION_STATUS.INSTALLING,
status_reason: 'Cannot connect',
+ can_uninstall: false,
},
{
name: 'cert_manager',
status: APPLICATION_STATUS.ERROR,
status_reason: 'Cannot connect',
email: 'test@example.com',
+ can_uninstall: false,
},
],
},
diff --git a/spec/frontend/clusters/stores/clusters_store_spec.js b/spec/frontend/clusters/stores/clusters_store_spec.js
index a20e0439555..aa926bb36d7 100644
--- a/spec/frontend/clusters/stores/clusters_store_spec.js
+++ b/spec/frontend/clusters/stores/clusters_store_spec.js
@@ -63,6 +63,8 @@ describe('Clusters Store', () => {
installed: false,
installFailed: false,
uninstallable: false,
+ uninstallSuccessful: false,
+ uninstallFailed: false,
},
ingress: {
title: 'Ingress',
@@ -74,6 +76,8 @@ describe('Clusters Store', () => {
installed: false,
installFailed: true,
uninstallable: false,
+ uninstallSuccessful: false,
+ uninstallFailed: false,
},
runner: {
title: 'GitLab Runner',
@@ -89,6 +93,8 @@ describe('Clusters Store', () => {
updateFailed: false,
updateSuccessful: false,
uninstallable: false,
+ uninstallSuccessful: false,
+ uninstallFailed: false,
},
prometheus: {
title: 'Prometheus',
@@ -98,6 +104,8 @@ describe('Clusters Store', () => {
installed: false,
installFailed: true,
uninstallable: false,
+ uninstallSuccessful: false,
+ uninstallFailed: false,
},
jupyter: {
title: 'JupyterHub',
@@ -108,6 +116,8 @@ describe('Clusters Store', () => {
installed: false,
installFailed: false,
uninstallable: false,
+ uninstallSuccessful: false,
+ uninstallFailed: false,
},
knative: {
title: 'Knative',
@@ -121,6 +131,8 @@ describe('Clusters Store', () => {
installed: false,
installFailed: false,
uninstallable: false,
+ uninstallSuccessful: false,
+ uninstallFailed: false,
},
cert_manager: {
title: 'Cert-Manager',
@@ -131,6 +143,8 @@ describe('Clusters Store', () => {
email: mockResponseData.applications[6].email,
installed: false,
uninstallable: false,
+ uninstallSuccessful: false,
+ uninstallFailed: false,
},
},
});