Deprecate xpack:defaultAdminEmail for monitoring alerts (#22195)

This commit is contained in:
Larry Gregory 2018-09-06 10:26:05 -04:00 committed by GitHub
parent 5f02f3e4ea
commit 5f96c903f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 245 additions and 45 deletions

View file

@ -46,8 +46,6 @@ To receive email notifications for the Cluster Alerts:
1. Configure an email account as described in
{xpack-ref}/actions-email.html#configuring-email[Configuring Email Accounts].
2. Navigate to the *Management* page in {kib}.
3. Go to the *Advanced Settings* page, find the `xpack:defaultAdminEmail`
setting, and enter your email address.
2. Configure the `xpack.monitoring.cluster_alerts.email_notifications.email_address` setting in `kibana.yml` with your email address.
Email notifications are sent only when Cluster Alerts are triggered and resolved.

View file

@ -112,4 +112,66 @@ describe('monitoring plugin deprecations', function () {
expect(log.called).to.be(false);
});
describe('cluster_alerts.email_notifications.email_address', function () {
it(`shouldn't log when email notifications are disabled`, function () {
const settings = {
cluster_alerts: {
email_notifications: {
enabled: false
}
}
};
const log = sinon.spy();
transformDeprecations(settings, log);
expect(log.called).to.be(false);
});
it(`shouldn't log when cluster alerts are disabled`, function () {
const settings = {
cluster_alerts: {
enabled: false,
email_notifications: {
enabled: true
}
}
};
const log = sinon.spy();
transformDeprecations(settings, log);
expect(log.called).to.be(false);
});
it(`shouldn't log when email_address is specified`, function () {
const settings = {
cluster_alerts: {
enabled: true,
email_notifications: {
enabled: true,
email_address: 'foo@bar.com'
}
}
};
const log = sinon.spy();
transformDeprecations(settings, log);
expect(log.called).to.be(false);
});
it(`should log when email_address is missing, but alerts/notifications are both enabled`, function () {
const settings = {
cluster_alerts: {
enabled: true,
email_notifications: {
enabled: true
}
}
};
const log = sinon.spy();
transformDeprecations(settings, log);
expect(log.called).to.be(true);
});
});
});

View file

@ -94,7 +94,7 @@ export const CALCULATE_DURATION_UNTIL = 'until';
/**
* In order to show ML Jobs tab in the Elasticsearch section / tab navigation, license must be supported
*/
export const ML_SUPPORTED_LICENSES = [ 'trial', 'platinum' ];
export const ML_SUPPORTED_LICENSES = ['trial', 'platinum'];
/**
* Metadata service URLs for the different cloud services that have constant URLs (e.g., unlike GCP, which is a constant prefix).
@ -135,7 +135,12 @@ export const DEFAULT_NO_DATA_MESSAGE_WITH_FILTER = (
);
export const TABLE_ACTION_UPDATE_FILTER = 'UPDATE_FILTER';
export const TABLE_ACTION_RESET_PAGING = 'RESET_PAGING';
export const TABLE_ACTION_RESET_PAGING = 'RESET_PAGING';
export const DEBOUNCE_SLOW_MS = 17; // roughly how long it takes to render a frame at 60fps
export const DEBOUNCE_FAST_MS = 10; // roughly how long it takes to render a frame at 100fps
/**
* Configuration key for setting the email address used for cluster alert notifications.
*/
export const CLUSTER_ALERTS_ADDRESS_CONFIG_KEY = 'cluster_alerts.email_notifications.email_address';

View file

@ -13,7 +13,7 @@ import { XPACK_INFO_API_DEFAULT_POLL_FREQUENCY_IN_MILLIS } from '../../server/li
*/
export const config = (Joi) => {
const { array, boolean, number, object, string } = Joi;
const DEFAULT_REQUEST_HEADERS = [ 'authorization' ];
const DEFAULT_REQUEST_HEADERS = ['authorization'];
return object({
ccs: object({
@ -49,7 +49,8 @@ export const config = (Joi) => {
enabled: boolean().default(true),
index: string().default('.monitoring-alerts-6'),
email_notifications: object({
enabled: boolean().default(true)
enabled: boolean().default(true),
email_address: string().email(),
}).default()
}).default(),
xpack_api_polling_frequency_millis: number().default(XPACK_INFO_API_DEFAULT_POLL_FREQUENCY_IN_MILLIS),

View file

@ -5,6 +5,7 @@
*/
import { get, has, set } from 'lodash';
import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY } from './common/constants';
/**
* Re-writes deprecated user-defined config settings and logs warnings as a
@ -29,12 +30,19 @@ export const deprecations = ({ rename }) => {
delete settings.elasticsearch.ssl.verify;
log('Config key "xpack.monitoring.elasticsearch.ssl.verify" is deprecated. ' +
'It has been replaced with "xpack.monitoring.elasticsearch.ssl.verificationMode"');
'It has been replaced with "xpack.monitoring.elasticsearch.ssl.verificationMode"');
},
(settings, log) => {
if (has(settings, 'report_stats')) {
log('Config key "xpack.monitoring.report_stats" is deprecated and will be removed in 7.0. ' +
'Use "xpack.xpack_main.telemetry.enabled" instead.');
'Use "xpack.xpack_main.telemetry.enabled" instead.');
}
},
(settings, log) => {
const clusterAlertsEnabled = get(settings, 'cluster_alerts.enabled');
const emailNotificationsEnabled = clusterAlertsEnabled && get(settings, 'cluster_alerts.email_notifications.enabled');
if (emailNotificationsEnabled && !get(settings, CLUSTER_ALERTS_ADDRESS_CONFIG_KEY)) {
log(`Config key "${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}" will be required for email notifications to work in 7.0."`);
}
},
];

View file

@ -8,27 +8,31 @@ import expect from 'expect.js';
import { checkForEmailValue } from '../get_settings_collector';
describe('getSettingsCollector / checkForEmailValue', () => {
const mockLogger = {
warn: () => { }
};
it('ignores shouldUseNull=true value and returns email if email value if one is set', async () => {
const shouldUseNull = true;
const getDefaultAdminEmailMock = () => 'test@elastic.co';
expect(await checkForEmailValue(undefined, undefined, shouldUseNull, getDefaultAdminEmailMock)).to.be('test@elastic.co');
expect(await checkForEmailValue(undefined, undefined, mockLogger, shouldUseNull, getDefaultAdminEmailMock)).to.be('test@elastic.co');
});
it('ignores shouldUseNull=false value and returns email if email value if one is set', async () => {
const shouldUseNull = false;
const getDefaultAdminEmailMock = () => 'test@elastic.co';
expect(await checkForEmailValue(undefined, undefined, shouldUseNull, getDefaultAdminEmailMock)).to.be('test@elastic.co');
expect(await checkForEmailValue(undefined, undefined, mockLogger, shouldUseNull, getDefaultAdminEmailMock)).to.be('test@elastic.co');
});
it('returns a null if no email value is set and null is allowed', async () => {
const shouldUseNull = true;
const getDefaultAdminEmailMock = () => null;
expect(await checkForEmailValue(undefined, undefined, shouldUseNull, getDefaultAdminEmailMock)).to.be(null);
expect(await checkForEmailValue(undefined, undefined, mockLogger, shouldUseNull, getDefaultAdminEmailMock)).to.be(null);
});
it('returns undefined if no email value is set and null is not allowed', async () => {
const shouldUseNull = false;
const getDefaultAdminEmailMock = () => null;
expect(await checkForEmailValue(undefined, undefined, shouldUseNull, getDefaultAdminEmailMock)).to.be(undefined);
expect(await checkForEmailValue(undefined, undefined, mockLogger, shouldUseNull, getDefaultAdminEmailMock)).to.be(undefined);
});
});

View file

@ -9,16 +9,23 @@ import sinon from 'sinon';
import { set } from 'lodash';
import { XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING } from '../../../../../../server/lib/constants';
import { getDefaultAdminEmail } from '../get_settings_collector';
import { getDefaultAdminEmail, resetDeprecationWarning } from '../get_settings_collector';
import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY } from '../../../../common/constants';
describe('getSettingsCollector / getDefaultAdminEmail', () => {
function setup({ enabled = true, docExists = true, adminEmail = 'admin@email.com' }) {
function setup({ enabled = true, docExists = true, defaultAdminEmail = 'default-admin@email.com', adminEmail = null }) {
const config = { get: sinon.stub() };
config.get
.withArgs('xpack.monitoring.cluster_alerts.email_notifications.enabled')
.returns(enabled);
if (adminEmail) {
config.get
.withArgs(`xpack.monitoring.${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}`)
.returns(adminEmail);
}
config.get
.withArgs('kibana.index')
.returns('.kibana');
@ -29,8 +36,8 @@ describe('getSettingsCollector / getDefaultAdminEmail', () => {
const doc = {};
if (docExists) {
if (adminEmail) {
set(doc, ['_source', 'config', XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING], adminEmail);
if (defaultAdminEmail) {
set(doc, ['_source', 'config', XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING], defaultAdminEmail);
} else {
set(doc, '_source.config', {});
}
@ -46,41 +53,131 @@ describe('getSettingsCollector / getDefaultAdminEmail', () => {
}))
.returns(doc);
const log = {
warn: sinon.stub()
};
return {
config,
callCluster
callCluster,
log,
};
}
describe('xpack.monitoring.cluster_alerts.email_notifications.enabled = false', () => {
it('returns null', async () => {
const { config, callCluster } = setup({ enabled: false });
expect(await getDefaultAdminEmail(config, callCluster)).to.be(null);
sinon.assert.notCalled(callCluster);
describe('using xpack:defaultAdminEmail', () => {
beforeEach(() => {
resetDeprecationWarning();
});
describe('xpack.monitoring.cluster_alerts.email_notifications.enabled = false', () => {
it('returns null', async () => {
const { config, callCluster, log } = setup({ enabled: false });
expect(await getDefaultAdminEmail(config, callCluster, log)).to.be(null);
sinon.assert.notCalled(callCluster);
});
it('does not log a deprecation warning', async () => {
const { config, callCluster, log } = setup({ enabled: false });
await getDefaultAdminEmail(config, callCluster, log);
sinon.assert.notCalled(log.warn);
});
});
describe('doc does not exist', () => {
it('returns null', async () => {
const { config, callCluster, log } = setup({ docExists: false });
expect(await getDefaultAdminEmail(config, callCluster, log)).to.be(null);
sinon.assert.calledOnce(callCluster);
});
it('logs a deprecation warning', async () => {
const { config, callCluster, log } = setup({ docExists: false });
await getDefaultAdminEmail(config, callCluster, log);
sinon.assert.calledOnce(log.warn);
});
});
describe('value is not defined', () => {
it('returns null', async () => {
const { config, callCluster, log } = setup({ defaultAdminEmail: false });
expect(await getDefaultAdminEmail(config, callCluster, log)).to.be(null);
sinon.assert.calledOnce(callCluster);
});
it('logs a deprecation warning', async () => {
const { config, callCluster, log } = setup({ defaultAdminEmail: false });
await getDefaultAdminEmail(config, callCluster, log);
sinon.assert.calledOnce(log.warn);
});
});
describe('value is defined', () => {
it('returns value', async () => {
const { config, callCluster, log } = setup({ defaultAdminEmail: 'hello@world' });
expect(await getDefaultAdminEmail(config, callCluster, log)).to.be('hello@world');
sinon.assert.calledOnce(callCluster);
});
it('logs a deprecation warning', async () => {
const { config, callCluster, log } = setup({ defaultAdminEmail: 'hello@world' });
await getDefaultAdminEmail(config, callCluster, log);
sinon.assert.calledOnce(log.warn);
});
});
});
describe('doc does not exist', () => {
it('returns null', async () => {
const { config, callCluster } = setup({ docExists: false });
expect(await getDefaultAdminEmail(config, callCluster)).to.be(null);
sinon.assert.calledOnce(callCluster);
describe('using xpack.monitoring.cluster_alerts.email_notifications.email_address', () => {
beforeEach(() => {
resetDeprecationWarning();
});
});
describe('value is not defined', () => {
it('returns null', async () => {
const { config, callCluster } = setup({ adminEmail: false });
expect(await getDefaultAdminEmail(config, callCluster)).to.be(null);
sinon.assert.calledOnce(callCluster);
describe('xpack.monitoring.cluster_alerts.email_notifications.enabled = false', () => {
it('returns null', async () => {
const { config, callCluster, log } = setup({ enabled: false });
expect(await getDefaultAdminEmail(config, callCluster, log)).to.be(null);
sinon.assert.notCalled(callCluster);
});
it('does not log a deprecation warning', async () => {
const { config, callCluster, log } = setup({ enabled: false });
await getDefaultAdminEmail(config, callCluster, log);
sinon.assert.notCalled(log.warn);
});
});
});
describe('value is defined', () => {
it('returns value', async () => {
const { config, callCluster } = setup({ adminEmail: 'hello@world' });
expect(await getDefaultAdminEmail(config, callCluster)).to.be('hello@world');
sinon.assert.calledOnce(callCluster);
describe('value is not defined', () => {
it('returns value from xpack:defaultAdminEmail', async () => {
const { config, callCluster, log } = setup({
defaultAdminEmail: 'default-admin@email.com',
adminEmail: false
});
expect(await getDefaultAdminEmail(config, callCluster, log)).to.be('default-admin@email.com');
sinon.assert.calledOnce(callCluster);
});
it('logs a deprecation warning', async () => {
const { config, callCluster, log } = setup({
defaultAdminEmail: 'default-admin@email.com',
adminEmail: false
});
await getDefaultAdminEmail(config, callCluster, log);
sinon.assert.calledOnce(log.warn);
});
});
describe('value is defined', () => {
it('returns value', async () => {
const { config, callCluster, log } = setup({ adminEmail: 'hello@world' });
expect(await getDefaultAdminEmail(config, callCluster, log)).to.be('hello@world');
sinon.assert.notCalled(callCluster);
});
it('does not log a deprecation warning', async () => {
const { config, callCluster, log } = setup({ adminEmail: 'hello@world' });
await getDefaultAdminEmail(config, callCluster, log);
sinon.assert.notCalled(log.warn);
});
});
});
});

View file

@ -6,24 +6,48 @@
import { get } from 'lodash';
import { XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING } from '../../../../../server/lib/constants';
import { KIBANA_SETTINGS_TYPE } from '../../../common/constants';
import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY, KIBANA_SETTINGS_TYPE } from '../../../common/constants';
let loggedDeprecationWarning = false;
export function resetDeprecationWarning() {
loggedDeprecationWarning = false;
}
/*
* Check if Cluster Alert email notifications is enabled in config
* If so, use uiSettings API to fetch the X-Pack default admin email
*/
export async function getDefaultAdminEmail(config, callCluster) {
export async function getDefaultAdminEmail(config, callCluster, log) {
if (!config.get('xpack.monitoring.cluster_alerts.email_notifications.enabled')) {
return null;
}
const emailAddressConfigKey = `xpack.monitoring.${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}`;
const configuredEmailAddress = config.get(emailAddressConfigKey);
if (configuredEmailAddress) {
return configuredEmailAddress;
}
// DEPRECATED (Remove below in 7.0): If an email address is not configured in kibana.yml, then fallback to xpack:defaultAdminEmail
if (!loggedDeprecationWarning) {
const message = (
`Monitoring is using ${XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING} for cluster alert notifications, ` +
`which will not be supported in Kibana 7.0. Please configure ${emailAddressConfigKey} in your kibana.yml settings`
);
log.warn(message);
loggedDeprecationWarning = true;
}
const index = config.get('kibana.index');
const version = config.get('pkg.version');
const uiSettingsDoc = await callCluster('get', {
index,
type: 'doc',
id: `config:${version}`,
ignore: [ 400, 404 ] // 400 if the index is closed, 404 if it does not exist
ignore: [400, 404] // 400 if the index is closed, 404 if it does not exist
});
return get(uiSettingsDoc, ['_source', 'config', XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING], null);
@ -35,10 +59,11 @@ let shouldUseNull = true;
export async function checkForEmailValue(
config,
callCluster,
log,
_shouldUseNull = shouldUseNull,
_getDefaultAdminEmail = getDefaultAdminEmail
) {
const defaultAdminEmail = await _getDefaultAdminEmail(config, callCluster);
const defaultAdminEmail = await _getDefaultAdminEmail(config, callCluster, log);
// Allow null so clearing the advanced setting will be reflected in the data
const isAcceptableNull = defaultAdminEmail === null && _shouldUseNull;
@ -61,7 +86,7 @@ export function getSettingsCollector(server) {
type: KIBANA_SETTINGS_TYPE,
async fetch(callCluster) {
let kibanaSettingsData;
const defaultAdminEmail = await checkForEmailValue(config, callCluster);
const defaultAdminEmail = await checkForEmailValue(config, callCluster, this.log);
// skip everything if defaultAdminEmail === undefined
if (defaultAdminEmail || (defaultAdminEmail === null && shouldUseNull)) {