From 7854ae24cc1b0ade78326cdf009b340ac96b697f Mon Sep 17 00:00:00 2001 From: chrisronline Date: Fri, 5 Feb 2021 17:28:00 -0500 Subject: [PATCH] Fix faulty license expiration logic --- .../alerts/license_expiration_alert.test.ts | 64 ++++++++++++++----- .../server/alerts/license_expiration_alert.ts | 11 ++-- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.test.ts index 849296adc0bb4..0d1c1d20097e5 100644 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.test.ts @@ -7,6 +7,7 @@ import { LicenseExpirationAlert } from './license_expiration_alert'; import { ALERT_LICENSE_EXPIRATION } from '../../common/constants'; +import { AlertSeverity } from '../../common/enums'; import { fetchLicenses } from '../lib/alerts/fetch_licenses'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; @@ -19,17 +20,8 @@ jest.mock('../lib/alerts/fetch_clusters', () => ({ fetchClusters: jest.fn(), })); jest.mock('moment', () => { - const moment = function () { - return { - format: () => 'THE_DATE', - }; - }; + const moment = function () {}; moment.duration = () => ({ humanize: () => 'HUMANIZED_DURATION' }); - moment.utc = () => ({ - add: () => ({ - isAfter: () => false, - }), - }); return moment; }); @@ -84,7 +76,7 @@ describe('LicenseExpirationAlert', () => { const license = { status: 'expired', type: 'gold', - expiryDateMS: 1, + expiryDateMS: 1000 * 60 * 60 * 24 * 59, clusterUuid, }; @@ -138,7 +130,7 @@ describe('LicenseExpirationAlert', () => { itemLabel: undefined, meta: { clusterUuid: 'abc123', - expiryDateMS: 1, + expiryDateMS: 5097600000, status: 'expired', type: 'gold', }, @@ -155,14 +147,14 @@ describe('LicenseExpirationAlert', () => { type: 'time', isRelative: true, isAbsolute: false, - timestamp: 1, + timestamp: 5097600000, }, { startToken: '#absolute', type: 'time', isAbsolute: true, isRelative: false, - timestamp: 1, + timestamp: 5097600000, }, { startToken: '#start_link', @@ -198,7 +190,7 @@ describe('LicenseExpirationAlert', () => { { status: 'active', type: 'gold', - expiryDateMS: 1, + expiryDateMS: 1000 * 60 * 60 * 24 * 61, clusterUuid, }, ]; @@ -213,5 +205,47 @@ describe('LicenseExpirationAlert', () => { expect(replaceState).not.toHaveBeenCalledWith({}); expect(scheduleActions).not.toHaveBeenCalled(); }); + + it('should use danger severity for a license expiring soon', async () => { + (fetchLicenses as jest.Mock).mockImplementation(() => { + return [ + { + status: 'active', + type: 'gold', + expiryDateMS: 1000 * 60 * 60 * 24 * 2, + clusterUuid, + }, + ]; + }); + const alert = new LicenseExpirationAlert(); + const type = alert.getAlertType(); + await type.executor({ + ...executorOptions, + // @ts-ignore + params: alert.alertOptions.defaultParams, + } as any); + expect(replaceState.mock.calls[0][0].alertStates[0].ui.severity).toBe(AlertSeverity.Danger); + }); + + it('should use warning severity for a license expiring in a bit', async () => { + (fetchLicenses as jest.Mock).mockImplementation(() => { + return [ + { + status: 'active', + type: 'gold', + expiryDateMS: 1000 * 60 * 60 * 24 * 31, + clusterUuid, + }, + ]; + }); + const alert = new LicenseExpirationAlert(); + const type = alert.getAlertType(); + await type.executor({ + ...executorOptions, + // @ts-ignore + params: alert.alertOptions.defaultParams, + } as any); + expect(replaceState.mock.calls[0][0].alertStates[0].ui.severity).toBe(AlertSeverity.Warning); + }); }); }); diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.ts index d25eda30b3071..24fbd98ef2e8b 100644 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { BaseAlert } from './base_alert'; @@ -91,7 +90,6 @@ export class LicenseExpirationAlert extends BaseAlert { return licenses.map((license) => { const { clusterUuid, type, expiryDateMS, status, ccs } = license; - const $expiry = moment.utc(expiryDateMS); let isExpired = false; let severity = AlertSeverity.Success; @@ -104,10 +102,10 @@ export class LicenseExpirationAlert extends BaseAlert { break; } - const $fromNow = moment.utc().add(EXPIRES_DAYS[i], 'days'); - if ($fromNow.isAfter($expiry)) { + const fromNow = +new Date() + EXPIRES_DAYS[i] * 1000 * 60 * 60 * 24; + if (fromNow >= expiryDateMS) { isExpired = true; - severity = i > 1 ? AlertSeverity.Warning : AlertSeverity.Danger; + severity = i < 1 ? AlertSeverity.Warning : AlertSeverity.Danger; break; } } @@ -167,8 +165,7 @@ export class LicenseExpirationAlert extends BaseAlert { // Logic in the base alert assumes that all alerts will operate against multiple nodes/instances (such as a CPU alert against ES nodes) // However, some alerts operate on the state of the cluster itself and are only concerned with a single state const state: AlertLicenseState = alertStates[0] as AlertLicenseState; - const $expiry = moment.utc(state.expiryDateMS); - const $duration = moment.duration(+new Date() - $expiry.valueOf()); + const $duration = moment.duration(+new Date() - state.expiryDateMS); const actionText = i18n.translate('xpack.monitoring.alerts.licenseExpiration.action', { defaultMessage: 'Please update your license.', });