GitLab ist jetzt auf dem neuesten Stand! Die jüngsten Probleme wurden behoben. Wir entschuldigen uns für die dadurch verursachten Unannehmlichkeiten.

Commit cf1b85dd authored by jerasmus's avatar jerasmus

Add ability to edit Knative domain

Added the functionality to edit the Knative domain
parent fd50ba42
......@@ -36,6 +36,7 @@ export default class Clusters {
installRunnerPath,
installJupyterPath,
installKnativePath,
updateKnativePath,
installPrometheusPath,
managePrometheusPath,
hasRbac,
......@@ -62,6 +63,7 @@ export default class Clusters {
installPrometheusEndpoint: installPrometheusPath,
installJupyterEndpoint: installJupyterPath,
installKnativeEndpoint: installKnativePath,
updateKnativeEndpoint: updateKnativePath,
});
this.installApplication = this.installApplication.bind(this);
......@@ -129,6 +131,8 @@ export default class Clusters {
eventHub.$on('upgradeApplication', data => this.upgradeApplication(data));
eventHub.$on('upgradeFailed', appId => this.upgradeFailed(appId));
eventHub.$on('dismissUpgradeSuccess', appId => this.dismissUpgradeSuccess(appId));
eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data));
eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data));
}
removeListeners() {
......@@ -137,6 +141,8 @@ export default class Clusters {
eventHub.$off('upgradeApplication', this.upgradeApplication);
eventHub.$off('upgradeFailed', this.upgradeFailed);
eventHub.$off('dismissUpgradeSuccess', this.dismissUpgradeSuccess);
eventHub.$off('saveKnativeDomain');
eventHub.$off('setKnativeHostname');
}
initPolling() {
......@@ -272,6 +278,18 @@ export default class Clusters {
this.store.updateAppProperty(appId, 'requestStatus', null);
}
saveKnativeDomain(data) {
const appId = data.id;
this.store.updateAppProperty(appId, 'status', APPLICATION_STATUS.UPDATING);
this.service.updateApplication(appId, data.params);
}
setKnativeHostname(data) {
const appId = data.id;
this.store.updateAppProperty(appId, 'isEditingHostName', true);
this.store.updateAppProperty(appId, 'hostname', data.hostname);
}
destroy() {
this.destroyed = true;
......
......@@ -191,14 +191,7 @@ export default {
return this.status === APPLICATION_STATUS.UPDATE_ERRORED;
},
upgradeFailureDescription() {
return sprintf(
s__(
'ClusterIntegration|Something went wrong when upgrading %{title}. Please check the logs and try again.',
),
{
title: this.title,
},
);
return s__('ClusterIntegration|Update failed. Please check the logs and try again.');
},
upgradeSuccessDescription() {
return sprintf(s__('ClusterIntegration|%{title} upgraded successfully.'), {
......@@ -210,9 +203,9 @@ export default {
if (this.upgradeAvailable && !this.upgradeFailed && !this.isUpgrading) {
label = s__('ClusterIntegration|Upgrade');
} else if (this.isUpgrading) {
label = s__('ClusterIntegration|Upgrading');
label = s__('ClusterIntegration|Updating');
} else if (this.upgradeFailed) {
label = s__('ClusterIntegration|Retry upgrade');
label = s__('ClusterIntegration|Retry update');
}
return label;
......@@ -224,6 +217,14 @@ export default {
(this.upgradeRequested && !this.upgradeSuccessful)
);
},
shouldShowUpgradeDetails() {
// This method only returns true when;
// Upgrade was successful OR Upgrade failed
// AND new upgrade is unavailable AND version information is present.
return (
(this.upgradeSuccessful || this.upgradeFailed) && !this.upgradeAvailable && this.version
);
},
},
watch: {
status() {
......@@ -303,7 +304,7 @@ export default {
</div>
<div
v-if="(upgradeSuccessful || upgradeFailed) && !upgradeAvailable"
v-if="shouldShowUpgradeDetails"
class="form-text text-muted label p-0 js-cluster-application-upgrade-details"
>
{{ versionLabel }}
......
......@@ -15,11 +15,14 @@ import { s__, sprintf } from '../../locale';
import applicationRow from './application_row.vue';
import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
import { CLUSTER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import eventHub from '~/clusters/event_hub';
export default {
components: {
applicationRow,
clipboardButton,
LoadingButton,
},
props: {
type: {
......@@ -173,16 +176,55 @@ export default {
jupyterHostname() {
return this.applications.jupyter.hostname;
},
knative() {
return this.applications.knative;
},
knativeInstalled() {
return this.applications.knative.status === APPLICATION_STATUS.INSTALLED;
return (
this.knative.status === APPLICATION_STATUS.INSTALLED ||
this.knativeUpgrading ||
this.knativeUpgradeFailed ||
this.knative.status === APPLICATION_STATUS.UPDATED
);
},
knativeUpgrading() {
return (
this.knative.status === APPLICATION_STATUS.UPDATING ||
this.knative.status === APPLICATION_STATUS.SCHEDULED
);
},
knativeUpgradeFailed() {
return this.knative.status === APPLICATION_STATUS.UPDATE_ERRORED;
},
knativeExternalIp() {
return this.applications.knative.externalIp;
return this.knative.externalIp;
},
canUpdateKnativeEndpoint() {
return this.knativeExternalIp && !this.knativeUpgradeFailed && !this.knativeUpgrading;
},
knativeHostname: {
get() {
return this.knative.hostname;
},
set(hostname) {
eventHub.$emit('setKnativeHostname', {
id: 'knative',
hostname,
});
},
},
},
created() {
this.helmInstallIllustration = helmInstallIllustration;
},
methods: {
saveKnativeDomain() {
eventHub.$emit('saveKnativeDomain', {
id: 'knative',
params: { hostname: this.knative.hostname },
});
},
},
};
</script>
......@@ -471,76 +513,88 @@ export default {
}}
</p>
<template v-if="knativeInstalled">
<div class="form-group">
<label for="knative-domainname">
{{ s__('ClusterIntegration|Knative Domain Name:') }}
</label>
<input
id="knative-domainname"
v-model="applications.knative.hostname"
type="text"
class="form-control js-domainname"
readonly
/>
</div>
</template>
<template v-else-if="helmInstalled && rbac">
<div class="form-group">
<label for="knative-domainname">
{{ s__('ClusterIntegration|Knative Domain Name:') }}
</label>
<input
id="knative-domainname"
v-model="applications.knative.hostname"
type="text"
class="form-control js-domainname"
/>
</div>
</template>
<template v-if="knativeInstalled">
<div class="form-group">
<label for="knative-ip-address">
{{ s__('ClusterIntegration|Knative IP Address:') }}
</label>
<div v-if="knativeExternalIp" class="input-group">
<div class="row">
<template v-if="knativeInstalled || (helmInstalled && rbac)">
<div
:class="{ 'col-md-6': knativeInstalled, 'col-12': helmInstalled && rbac }"
class="form-group col-sm-12 mb-0"
>
<label for="knative-domainname">
<strong>
{{ s__('ClusterIntegration|Knative Domain Name:') }}
</strong>
</label>
<input
id="knative-ip-address"
:value="knativeExternalIp"
id="knative-domainname"
v-model="knativeHostname"
type="text"
class="form-control js-ip-address"
readonly
class="form-control js-knative-domainname"
/>
<span class="input-group-append">
<clipboard-button
:text="knativeExternalIp"
:title="s__('ClusterIntegration|Copy Knative IP Address to clipboard')"
class="input-group-text js-clipboard-btn"
</div>
</template>
<template v-if="knativeInstalled">
<div class="form-group col-sm-12 col-md-6 pl-md-0 mb-0 mt-3 mt-md-0">
<label for="knative-ip-address">
<strong>
{{ s__('ClusterIntegration|Knative Endpoint:') }}
</strong>
</label>
<div v-if="knativeExternalIp" class="input-group">
<input
id="knative-ip-address"
:value="knativeExternalIp"
type="text"
class="form-control js-knative-ip-address"
readonly
/>
</span>
<span class="input-group-append">
<clipboard-button
:text="knativeExternalIp"
:title="s__('ClusterIntegration|Copy Knative Endpoint to clipboard')"
class="input-group-text js-knative-ip-clipboard-btn"
/>
</span>
</div>
<input
v-else
type="text"
class="form-control js-knative-ip-address"
readonly
value="?"
/>
</div>
<input v-else type="text" class="form-control js-ip-address" readonly value="?" />
</div>
<p v-if="!knativeExternalIp" class="settings-message js-no-ip-message">
{{
s__(`ClusterIntegration|The IP address is in
the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}}
</p>
<p class="form-text text-muted col-12">
{{
s__(
`ClusterIntegration|To access your application after deployment, point a wildcard DNS to the Knative Endpoint.`,
)
}}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }}
</a>
</p>
<p>
{{
s__(`ClusterIntegration|Point a wildcard DNS to this
generated IP address in order to access
your application after it has been deployed.`)
}}
<a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }}
</a>
</p>
</template>
<p
v-if="!knativeExternalIp"
class="settings-message js-no-knative-ip-message mt-2 mr-3 mb-0 ml-3 "
>
{{
s__(`ClusterIntegration|The IP address is in
the process of being assigned. Please check your Kubernetes
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
}}
</p>
<button
v-if="canUpdateKnativeEndpoint"
class="btn btn-success js-knative-save-domain-button mt-3 ml-3"
@click="saveKnativeDomain"
>
{{ s__('ClusterIntegration|Save changes') }}
</button>
</template>
</div>
</div>
</application-row>
</div>
......
......@@ -12,6 +12,9 @@ export default class ClusterService {
jupyter: this.options.installJupyterEndpoint,
knative: this.options.installKnativeEndpoint,
};
this.appUpdateEndpointMap = {
knative: this.options.updateKnativeEndpoint,
};
}
fetchData() {
......@@ -22,6 +25,10 @@ export default class ClusterService {
return axios.post(this.appInstallEndpointMap[appId], params);
}
updateApplication(appId, params) {
return axios.patch(this.appUpdateEndpointMap[appId], params);
}
static updateCluster(endpoint, data) {
return axios.put(endpoint, data);
}
......
......@@ -66,6 +66,7 @@ export default class ClusterStore {
requestStatus: null,
requestReason: null,
hostname: null,
isEditingHostName: false,
externalIp: null,
},
},
......@@ -129,8 +130,10 @@ export default class ClusterStore {
? `jupyter.${this.state.applications.ingress.externalIp}.nip.io`
: '');
} else if (appId === KNATIVE) {
this.state.applications.knative.hostname =
serverAppEntry.hostname || this.state.applications.knative.hostname;
if (!this.state.applications.knative.isEditingHostName) {
this.state.applications.knative.hostname =
serverAppEntry.hostname || this.state.applications.knative.hostname;
}
this.state.applications.knative.externalIp =
serverAppEntry.external_ip || this.state.applications.knative.externalIp;
} else if (appId === RUNNER) {
......
---
title: Edit Knative domain after it has been deployed
merge_request: 25386
author:
type: added
......@@ -1683,7 +1683,7 @@ msgstr ""
msgid "ClusterIntegration|Copy Jupyter Hostname to clipboard"
msgstr ""
msgid "ClusterIntegration|Copy Knative IP Address to clipboard"
msgid "ClusterIntegration|Copy Knative Endpoint to clipboard"
msgstr ""
msgid "ClusterIntegration|Copy Kubernetes cluster name"
......@@ -1806,7 +1806,7 @@ msgstr ""
msgid "ClusterIntegration|Knative Domain Name:"
msgstr ""
msgid "ClusterIntegration|Knative IP Address:"
msgid "ClusterIntegration|Knative Endpoint:"
msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
......@@ -1926,7 +1926,7 @@ msgstr ""
msgid "ClusterIntegration|Request to begin installing failed"
msgstr ""
msgid "ClusterIntegration|Retry upgrade"
msgid "ClusterIntegration|Retry update"
msgstr ""
msgid "ClusterIntegration|Save changes"
......@@ -1971,9 +1971,6 @@ msgstr ""
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
msgid "ClusterIntegration|Something went wrong when upgrading %{title}. Please check the logs and try again."
msgstr ""
msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster on Google Kubernetes Engine"
msgstr ""
......@@ -1992,12 +1989,21 @@ msgstr ""
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
msgid "ClusterIntegration|To access your application after deployment, point a wildcard DNS to the Knative Endpoint."
msgstr ""
msgid "ClusterIntegration|Toggle Kubernetes cluster"
msgstr ""
msgid "ClusterIntegration|Token"
msgstr ""
msgid "ClusterIntegration|Update failed. Please check the logs and try again."
msgstr ""
msgid "ClusterIntegration|Updating"
msgstr ""
msgid "ClusterIntegration|Upgrade"
msgstr ""
......
......@@ -230,7 +230,7 @@ describe('Application Row', () => {
expect(upgradeBtn.innerHTML).toContain('Upgrade');
});
it('has enabled "Retry upgrade" when APPLICATION_STATUS.UPDATE_ERRORED', () => {
it('has enabled "Retry update" when APPLICATION_STATUS.UPDATE_ERRORED', () => {
vm = mountComponent(ApplicationRow, {
...DEFAULT_APPLICATION_STATE,
status: APPLICATION_STATUS.UPDATE_ERRORED,
......@@ -239,10 +239,10 @@ describe('Application Row', () => {
expect(upgradeBtn).not.toBe(null);
expect(vm.upgradeFailed).toBe(true);
expect(upgradeBtn.innerHTML).toContain('Retry upgrade');
expect(upgradeBtn.innerHTML).toContain('Retry update');
});
it('has disabled "Retry upgrade" when APPLICATION_STATUS.UPDATING', () => {
it('has disabled "Updating" when APPLICATION_STATUS.UPDATING', () => {
vm = mountComponent(ApplicationRow, {
...DEFAULT_APPLICATION_STATE,
status: APPLICATION_STATUS.UPDATING,
......@@ -251,7 +251,7 @@ describe('Application Row', () => {
expect(upgradeBtn).not.toBe(null);
expect(vm.isUpgrading).toBe(true);
expect(upgradeBtn.innerHTML).toContain('Upgrading');
expect(upgradeBtn.innerHTML).toContain('Updating');
});
it('clicking upgrade button emits event', () => {
......@@ -295,7 +295,7 @@ describe('Application Row', () => {
expect(failureMessage).not.toBe(null);
expect(failureMessage.innerHTML).toContain(
'Something went wrong when upgrading GitLab Runner. Please check the logs and try again.',
'Update failed. Please check the logs and try again.',
);
});
});
......
import Vue from 'vue';
import applications from '~/clusters/components/applications.vue';
import { CLUSTER_TYPE } from '~/clusters/constants';
import eventHub from '~/clusters/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { APPLICATIONS_MOCK_STATE } from '../services/mock_data';
describe('Applications', () => {
let vm;
......@@ -18,16 +20,8 @@ describe('Applications', () => {
describe('Project cluster applications', () => {
beforeEach(() => {
vm = mountComponent(Applications, {
applications: APPLICATIONS_MOCK_STATE,
type: CLUSTER_TYPE.PROJECT,
applications: {
helm: { title: 'Helm Tiller' },
ingress: { title: 'Ingress' },
cert_manager: { title: 'Cert-Manager' },
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub' },
knative: { title: 'Knative' },
},
});
});
......@@ -64,15 +58,7 @@ describe('Applications', () => {
beforeEach(() => {
vm = mountComponent(Applications, {
type: CLUSTER_TYPE.GROUP,
applications: {
helm: { title: 'Helm Tiller' },
ingress: { title: 'Ingress' },
cert_manager: { title: 'Cert-Manager' },
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub' },
knative: { title: 'Knative' },
},
applications: APPLICATIONS_MOCK_STATE,
});
});
......@@ -111,17 +97,12 @@ describe('Applications', () => {
it('renders ip address with a clipboard button', () => {
vm = mountComponent(Applications, {
applications: {
...APPLICATIONS_MOCK_STATE,
ingress: {
title: 'Ingress',
status: 'installed',
externalIp: '0.0.0.0',
},
helm: { title: 'Helm Tiller' },
cert_manager: { title: 'Cert-Manager' },
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '' },
knative: { title: 'Knative', hostname: '' },
},
});
......@@ -137,16 +118,11 @@ describe('Applications', () => {
it('renders an input text with a question mark and an alert text', () => {
vm = mountComponent(Applications, {
applications: {
...APPLICATIONS_MOCK_STATE,
ingress: {
title: 'Ingress',
status: 'installed',
},
helm: { title: 'Helm Tiller' },
cert_manager: { title: 'Cert-Manager' },
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '' },
knative: { title: 'Knative', hostname: '' },
},
});
......@@ -160,15 +136,7 @@ describe('Applications', () => {
describe('before installing', () => {
it('does not render the IP address', () => {
vm = mountComponent(Applications, {
applications: {
helm: { title: 'Helm Tiller' },
ingress: { title: 'Ingress' },
cert_manager: { title: 'Cert-Manager' },
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '' },
knative: { title: 'Knative', hostname: '' },
},
applications: APPLICATIONS_MOCK_STATE,
});
expect(vm.$el.textContent).not.toContain('Ingress IP Address');
......@@ -181,17 +149,12 @@ describe('Applications', () => {
it('renders email & allows editing', () => {
vm = mountComponent(Applications, {
applications: {
helm: { title: 'Helm Tiller', status: 'installed' },
ingress: { title: 'Ingress', status: 'installed', externalIp: '1.1.1.1' },
...APPLICATIONS_MOCK_STATE,
cert_manager: {
title: 'Cert-Manager',
email: 'before@example.com',
status: 'installable',
},
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' },
knative: { title: 'Knative', hostname: '', status: 'installable' },
},
});
......@@ -204,17 +167,12 @@ describe('Applications', () => {
it('renders email in readonly', () => {
vm = mountComponent(Applications, {
applications: {
helm: { title: 'Helm Tiller', status: 'installed' },
ingress: { title: 'Ingress', status: 'installed', externalIp: '1.1.1.1' },
...APPLICATIONS_MOCK_STATE,
cert_manager: {
title: 'Cert-Manager',
email: 'after@example.com',
status: 'installed',
},
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' },
knative: { title: 'Knative', hostname: '', status: 'installable' },
},
});
......@@ -229,13 +187,12 @@ describe('Applications', () => {
it('renders hostname active input', () => {
vm = mountComponent(Applications, {
applications: {
helm: { title: 'Helm Tiller', status: 'installed' },
ingress: { title: 'Ingress', status: 'installed', externalIp: '1.1.1.1' },
cert_manager: { title: 'Cert-Manager' },
runner: { title: 'GitLab Runner' },
prometheus: { title: 'Prometheus' },
jupyter: { title: 'JupyterHub', hostname: '', status: 'installable' },
knative: { title: 'Knative', hostname: '', status: 'installable' },
...APPLICATIONS_MOCK_STATE,
ingress: {