Commit 9b40298c authored by Peter Leitzen's avatar Peter Leitzen Committed by Filipa Lacerda

Resolve "Support alerts from external Prometheus servers" ~frontend

parent 85520a43
...@@ -8,3 +8,5 @@ ...@@ -8,3 +8,5 @@
.col-lg-9 .col-lg-9
= render 'projects/services/prometheus/metrics', project: @project = render 'projects/services/prometheus/metrics', project: @project
= render_if_exists 'projects/services/prometheus/external_alerts', project: @project
import IntegrationSettingsForm from '~/integrations/integration_settings_form'; import IntegrationSettingsForm from '~/integrations/integration_settings_form';
import PrometheusMetrics from 'ee/prometheus_metrics/prometheus_metrics'; import PrometheusMetrics from 'ee/prometheus_metrics/prometheus_metrics';
import PrometheusAlerts from 'ee/prometheus_alerts';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
...@@ -14,4 +15,6 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -14,4 +15,6 @@ document.addEventListener('DOMContentLoaded', () => {
prometheusMetrics.setNoIntegrationActiveState(); prometheusMetrics.setNoIntegrationActiveState();
} }
} }
PrometheusAlerts();
}); });
<script>
import { GlButton, GlFormGroup, GlFormInput, GlModal, GlModalDirective } from '@gitlab/ui';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import axios from '~/lib/utils/axios_utils';
import { __, sprintf } from '~/locale';
import createFlash from '~/flash';
export default {
copyToClipboard: __('Copy to clipboard'),
components: {
GlButton,
GlFormGroup,
GlFormInput,
GlModal,
ClipboardButton,
},
directives: {
'gl-modal': GlModalDirective,
},
props: {
initialAuthorizationKey: {
type: String,
required: false,
default: '',
},
changeKeyUrl: {
type: String,
required: true,
},
notifyUrl: {
type: String,
required: true,
},
learnMoreUrl: {
type: String,
required: true,
},
},
data() {
return {
authorizationKey: this.initialAuthorizationKey,
sectionDescription: sprintf(
__(
'To receive alerts from manually configured Prometheus services, add the following URL and Authorization key to your Prometheus webhook config file. Learn more about %{linkStart}configuring Prometheus%{linkEnd} to send alerts to GitLab.',
),
{
linkStart: `<a href="${this.learnMoreUrl}" target="_blank" rel="noopener noreferrer">`,
linkEnd: '</a>',
},
false,
),
};
},
methods: {
resetKey() {
axios
.post(this.changeKeyUrl)
.then(res => {
this.authorizationKey = res.data.token;
})
.catch(() => {
createFlash(__('Failed to reset key. Please try again.'));
});
},
},
};
</script>
<template>
<div class="row py-4 border-top js-prometheus-alerts">
<div class="col-lg-3">
<h4 class="mt-0">
{{ __('Alerts') }}
</h4>
<p>
{{ __('Receive alerts from manually configured Prometheus servers.') }}
</p>
</div>
<div class="col-lg-9">
<p v-html="sectionDescription"></p>
<gl-form-group :label="__('URL')" label-for="notify-url" label-class="label-bold">
<div class="input-group">
<gl-form-input id="notify-url" :readonly="true" :value="notifyUrl" />
<span class="input-group-append">
<clipboard-button :text="notifyUrl" :title="$options.copyToClipboard" />
</span>
</div>
</gl-form-group>
<gl-form-group
:label="__('Authorization key')"
label-for="authorization-key"
label-class="label-bold"
>
<div class="input-group">
<gl-form-input id="authorization-key" :readonly="true" :value="authorizationKey" />
<span class="input-group-append">
<clipboard-button :text="authorizationKey" :title="$options.copyToClipboard" />
</span>
</div>
</gl-form-group>
<template v-if="authorizationKey.length > 0">
<gl-modal
modal-id="authKeyModal"
:title="__('Reset authorization key?')"
:ok-title="__('Reset authorization key')"
ok-variant="danger"
@ok="resetKey"
>
{{
__(
'Resetting the authorization key will invalidate the previous key. Existing alert configurations will need to be updated with the new key.',
)
}}
</gl-modal>
<gl-button v-gl-modal.authKeyModal class="js-reset-auth-key">{{
__('Reset key')
}}</gl-button>
</template>
<gl-button v-else class="js-reset-auth-key" @click="resetKey">{{
__('Generate key')
}}</gl-button>
</div>
</div>
</template>
import Vue from 'vue';
import ResetKey from './components/reset_key.vue';
export default () => {
const el = document.querySelector('#js-settings-prometheus-alerts');
const { authorizationKey, changeKeyUrl, notifyUrl, learnMoreUrl } = el.dataset;
// eslint-disable-next-line no-new
new Vue({
el,
render(createElement) {
return createElement(ResetKey, {
props: {
initialAuthorizationKey: authorizationKey,
changeKeyUrl,
notifyUrl,
learnMoreUrl,
},
});
},
});
};
- return unless can?(current_user, :read_prometheus_alerts, @project)
- notify_url = notify_project_prometheus_alerts_url(@project, format: :json)
- authorization_key = @project.alerting_setting.try(:token)
- learn_more_url = help_page_path('administration/monitoring/prometheus/index', anchor: 'configuring-prometheus')
#js-settings-prometheus-alerts{ data: { notify_url: notify_url, authorization_key: authorization_key, change_key_url: reset_alerting_token_project_settings_operations_path(@project), learn_more_url: learn_more_url } }
import { shallowMount, createLocalVue } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import ResetKey from 'ee/prometheus_alerts/components/reset_key.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { GlModal } from '@gitlab/ui';
describe('ResetKey', () => {
let Component;
let mock;
let vm;
const localVue = createLocalVue();
const propsData = {
initialAuthorizationKey: 'abcd1234',
changeKeyUrl: '/updateKeyUrl',
notifyUrl: '/root/autodevops-deploy/prometheus/alerts/notify.json',
learnMoreUrl: '/learnMore',
};
beforeEach(() => {
mock = new MockAdapter(axios);
Component = localVue.extend(ResetKey);
setFixtures('<div class="flash-container"></div><div id="reset-key"></div>');
});
afterEach(() => {
mock.restore();
vm.destroy();
});
describe('authorization key exists', () => {
beforeEach(() => {
propsData.initialAuthorizationKey = 'abcd1234';
vm = shallowMount(Component, {
propsData,
});
});
it('shows fields and buttons', () => {
expect(vm.find('#notify-url').attributes('value')).toEqual(propsData.notifyUrl);
expect(vm.find('#authorization-key').attributes('value')).toEqual(
propsData.initialAuthorizationKey,
);
expect(vm.findAll(ClipboardButton).length).toBe(2);
expect(vm.find('.js-reset-auth-key').text()).toEqual('Reset key');
});
it('reset updates key', done => {
mock.onPost(propsData.changeKeyUrl).replyOnce(200, { token: 'newToken' });
vm.find(GlModal).vm.$emit('ok');
setTimeout(() => {
expect(vm.find('#authorization-key').attributes('value')).toEqual('newToken');
done();
});
});
it('reset key failure shows error', done => {
mock.onPost(propsData.changeKeyUrl).replyOnce(500);
vm.find(GlModal).vm.$emit('ok');
setTimeout(() => {
expect(vm.find('#authorization-key').attributes('value')).toEqual(
propsData.initialAuthorizationKey,
);
expect(document.querySelector('.flash-container').innerText.trim()).toEqual(
'Failed to reset key. Please try again.',
);
done();
});
});
});
describe('authorization key has not been set', () => {
beforeEach(() => {
propsData.initialAuthorizationKey = '';
vm = shallowMount(Component, {
propsData,
});
});
it('shows Generate Key button', () => {
expect(vm.find('.js-reset-auth-key').text()).toEqual('Generate key');
expect(vm.find('#authorization-key').attributes('value')).toEqual('');
});
it('Generate key button triggers key change', done => {
mock.onPost(propsData.changeKeyUrl).replyOnce(200, { token: 'newToken' });
vm.find('.js-reset-auth-key').vm.$emit('click');
setTimeout(() => {
expect(vm.find('#authorization-key').attributes('value')).toEqual('newToken');
done();
});
});
});
});
...@@ -607,6 +607,9 @@ msgid_plural "Alerts" ...@@ -607,6 +607,9 @@ msgid_plural "Alerts"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "Alerts"
msgstr ""
msgid "All" msgid "All"
msgstr "" msgstr ""
...@@ -1051,6 +1054,9 @@ msgstr "" ...@@ -1051,6 +1054,9 @@ msgstr ""
msgid "Authorization code:" msgid "Authorization code:"
msgstr "" msgstr ""
msgid "Authorization key"
msgstr ""
msgid "Authorization was granted by entering your username and password in the application." msgid "Authorization was granted by entering your username and password in the application."
msgstr "" msgstr ""
...@@ -3800,6 +3806,9 @@ msgstr "" ...@@ -3800,6 +3806,9 @@ msgstr ""
msgid "Failed to remove the pipeline schedule" msgid "Failed to remove the pipeline schedule"
msgstr "" msgstr ""
msgid "Failed to reset key. Please try again."
msgstr ""
msgid "Failed to signing using smartcard authentication" msgid "Failed to signing using smartcard authentication"
msgstr "" msgstr ""
...@@ -4148,6 +4157,9 @@ msgstr "" ...@@ -4148,6 +4157,9 @@ msgstr ""
msgid "Generate a default set of labels" msgid "Generate a default set of labels"
msgstr "" msgstr ""
msgid "Generate key"
msgstr ""
msgid "Geo" msgid "Geo"
msgstr "" msgstr ""
...@@ -7607,6 +7619,9 @@ msgstr "" ...@@ -7607,6 +7619,9 @@ msgstr ""
msgid "Real-time features" msgid "Real-time features"
msgstr "" msgstr ""
msgid "Receive alerts from manually configured Prometheus servers."
msgstr ""
msgid "Recent searches" msgid "Recent searches"
msgstr "" msgstr ""
...@@ -7825,12 +7840,24 @@ msgstr "" ...@@ -7825,12 +7840,24 @@ msgstr ""
msgid "Resend invite" msgid "Resend invite"
msgstr "" msgstr ""
msgid "Reset authorization key"
msgstr ""
msgid "Reset authorization key?"
msgstr ""
msgid "Reset health check access token" msgid "Reset health check access token"
msgstr "" msgstr ""
msgid "Reset key"
msgstr ""
msgid "Reset runners registration token" msgid "Reset runners registration token"
msgstr "" msgstr ""
msgid "Resetting the authorization key will invalidate the previous key. Existing alert configurations will need to be updated with the new key."
msgstr ""
msgid "Resolve all discussions in new issue" msgid "Resolve all discussions in new issue"
msgstr "" msgstr ""
...@@ -9765,6 +9792,9 @@ msgstr "" ...@@ -9765,6 +9792,9 @@ msgstr ""
msgid "To preserve performance only <strong>%{display_size} of %{real_size}</strong> files are displayed." msgid "To preserve performance only <strong>%{display_size} of %{real_size}</strong> files are displayed."
msgstr "" msgstr ""
msgid "To receive alerts from manually configured Prometheus services, add the following URL and Authorization key to your Prometheus webhook config file. Learn more about %{linkStart}configuring Prometheus%{linkEnd} to send alerts to GitLab."
msgstr ""
msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:" msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:"
msgstr "" msgstr ""
...@@ -9909,6 +9939,9 @@ msgstr "" ...@@ -9909,6 +9939,9 @@ msgstr ""
msgid "Type" msgid "Type"
msgstr "" msgstr ""
msgid "URL"
msgstr ""
msgid "Unable to load the diff. %{button_try_again}" msgid "Unable to load the diff. %{button_try_again}"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment