[Reporting] Consolidate startup self-checks (#31931) (#33213)

* [Reporting] Open test page in reporting browser self-check

* comment correction

* fix tests

* fix test

* fix tests more

* remove test of open Kibana URL
This commit is contained in:
Tim Sullivan 2019-03-14 09:22:55 -07:00 committed by GitHub
parent b7113c02e4
commit 87357b3ef7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 121 additions and 86 deletions

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { createMockServer } from '../../../test_helpers/create_mock_server';
import { createMockServer } from '../test_helpers/create_mock_server';
import { getAbsoluteUrlFactory } from './get_absolute_url';
test(`by default it builds url using information from server.info.protocol and the server.config`, () => {

View file

@ -6,8 +6,8 @@
import url from 'url';
// @ts-ignore
import { oncePerServer } from '../../../server/lib/once_per_server';
import { ConfigObject, KbnServer } from '../../../types';
import { oncePerServer } from '../server/lib/once_per_server';
import { ConfigObject, KbnServer } from '../types';
function getAbsoluteUrlFn(server: KbnServer) {
const config: ConfigObject = server.config();

View file

@ -5,8 +5,8 @@
*/
// @ts-ignore
import url from 'url';
import { getAbsoluteUrlFactory } from '../../../common/get_absolute_url';
import { ConditionalHeaders, KbnServer, ReportingJob } from '../../../types';
import { getAbsoluteUrlFactory } from './get_absolute_url';
function getSavedObjectAbsoluteUrl(job: ReportingJob, relativeUrl: string, server: KbnServer) {
const getAbsoluteUrl: any = getAbsoluteUrlFactory(server);

View file

@ -9,4 +9,3 @@ export { decryptJobHeaders } from './decrypt_job_headers';
export { getConditionalHeaders } from './get_conditional_headers';
export { getCustomLogo } from './get_custom_logo';
export { omitBlacklistedHeaders } from './omit_blacklisted_headers';
export { getAbsoluteUrlFactory } from './get_absolute_url';

View file

@ -5,7 +5,7 @@
*/
import url from 'url';
import { getAbsoluteUrlFactory } from '../../../common/execute_job/get_absolute_url';
import { getAbsoluteUrlFactory } from '../../../../common/get_absolute_url';
import { i18n } from '@kbn/i18n';
export function compatibilityShimFactory(server) {

View file

@ -12,9 +12,7 @@ import { registerRoutes } from './server/routes';
import { createQueueFactory } from './server/lib/create_queue';
import { config as appConfig } from './server/config/config';
import { checkLicenseFactory } from './server/lib/check_license';
import { validateConfig } from './server/lib/validate_config';
import { validateMaxContentLength } from './server/lib/validate_max_content_length';
import { validateBrowser } from './server/lib/validate_browser';
import { runValidations } from './server/lib/validate';
import { exportTypesRegistryFactory } from './server/lib/export_types_registry';
import { CHROMIUM, createBrowserDriverFactory, getDefaultChromiumSandboxDisabled } from './server/browsers';
import { logConfiguration } from './log_configuration';
@ -149,15 +147,14 @@ export const reporting = (kibana) => {
server.expose('exportTypesRegistry', exportTypesRegistry);
const config = server.config();
const logWarning = message => server.log(['reporting', 'warning'], message);
validateConfig(config, logWarning);
validateMaxContentLength(server, logWarning);
validateBrowser(browserFactory, logWarning);
logConfiguration(config, message => server.log(['reporting', 'debug'], message));
const logger = {
debug: message => server.log(['reporting', 'debug'], message),
warning: message => server.log(['reporting', 'warning'], message),
};
logConfiguration(config, logger);
runValidations(server, config, logger, browserFactory);
const { xpack_main: xpackMainPlugin } = server.plugins;
mirrorPluginStatus(xpackMainPlugin, this);
const checkLicense = checkLicenseFactory(exportTypesRegistry);
xpackMainPlugin.status.once('green', () => {

View file

@ -9,14 +9,14 @@ import { promisify } from 'util';
const getos = promisify(getosSync);
export async function logConfiguration(config, log) {
export async function logConfiguration(config, logger) {
const browserType = config.get('xpack.reporting.capture.browser.type');
log(`Browser type: ${browserType}`);
logger.debug(`Browser type: ${browserType}`);
if (browserType === 'chromium') {
log(`Chromium sandbox disabled: ${config.get('xpack.reporting.capture.browser.chromium.disableSandbox')}`);
logger.debug(`Chromium sandbox disabled: ${config.get('xpack.reporting.capture.browser.chromium.disableSandbox')}`);
}
const os = await getos();
log(`Running on os "${os.os}", distribution "${os.dist}", release "${os.release}"`);
logger.debug(`Running on os "${os.os}", distribution "${os.dist}", release "${os.release}"`);
}

View file

@ -28,7 +28,7 @@ export class HeadlessChromiumDriverFactory {
type = 'chromium';
test({ viewport, browserTimezone }, log) {
test({ viewport, browserTimezone }, logger) {
const userDataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'chromium-'));
const chromiumArgs = args({
userDataDir,
@ -49,10 +49,10 @@ export class HeadlessChromiumDriverFactory {
},
})
.catch(error => {
log(
logger.warning(
`The Reporting plugin encountered issues launching Chromium in a self-test. You may have trouble generating reports: [${error}]`
);
log(`See Chromium's log output at "${getChromeLogLocation(this.binaryPath)}"`);
logger.warning(`See Chromium's log output at "${getChromeLogLocation(this.binaryPath)}"`);
return null;
});
}

View file

@ -8,25 +8,27 @@ import expect from 'expect.js';
import sinon from 'sinon';
import { validateConfig } from '../validate_config';
describe('Reporting: Validate config', function () {
const log = sinon.spy();
describe('Reporting: Validate config', () => {
const logger = {
warning: sinon.spy(),
};
beforeEach(() => {
log.resetHistory();
logger.warning.resetHistory();
});
[undefined, null].forEach(value => {
it(`should log a warning and set xpack.reporting.encryptionKey if encryptionKey is ${value}`, function () {
it(`should log a warning and set xpack.reporting.encryptionKey if encryptionKey is ${value}`, () => {
const config = {
get: sinon.stub().returns(value),
set: sinon.stub()
set: sinon.stub(),
};
expect(() => validateConfig(config, log)).not.to.throwError();
expect(() => validateConfig(config, logger)).not.to.throwError();
sinon.assert.calledWith(config.set, 'xpack.reporting.encryptionKey');
sinon.assert.calledWithMatch(log, /Generating a random key/);
sinon.assert.calledWithMatch(log, /please set xpack.reporting.encryptionKey/);
sinon.assert.calledWithMatch(logger.warning, /Generating a random key/);
sinon.assert.calledWithMatch(logger.warning, /please set xpack.reporting.encryptionKey/);
});
});
});

View file

@ -11,10 +11,12 @@ const FIVE_HUNDRED_MEGABYTES = 524288000;
const ONE_HUNDRED_MEGABYTES = 104857600;
describe('Reporting: Validate Max Content Length', () => {
const log = sinon.spy();
const logger = {
warning: sinon.spy(),
};
beforeEach(() => {
log.resetHistory();
logger.warning.resetHistory();
});
it('should log warning messages when reporting has a higher max-size than elasticsearch', async () => {
@ -37,12 +39,12 @@ describe('Reporting: Validate Max Content Length', () => {
},
};
await validateMaxContentLength(server, log);
await validateMaxContentLength(server, logger);
sinon.assert.calledWithMatch(log, `xpack.reporting.csv.maxSizeBytes (524288000) is higher`);
sinon.assert.calledWithMatch(log, `than ElasticSearch's http.max_content_length (104857600)`);
sinon.assert.calledWithMatch(log, 'Please set http.max_content_length in ElasticSearch to match');
sinon.assert.calledWithMatch(log, 'or lower your xpack.reporting.csv.maxSizeBytes in Kibana');
sinon.assert.calledWithMatch(logger.warning, `xpack.reporting.csv.maxSizeBytes (524288000) is higher`);
sinon.assert.calledWithMatch(logger.warning, `than ElasticSearch's http.max_content_length (104857600)`);
sinon.assert.calledWithMatch(logger.warning, 'Please set http.max_content_length in ElasticSearch to match');
sinon.assert.calledWithMatch(logger.warning, 'or lower your xpack.reporting.csv.maxSizeBytes in Kibana');
});
it('should do nothing when reporting has the same max-size as elasticsearch', async () => {
@ -65,7 +67,7 @@ describe('Reporting: Validate Max Content Length', () => {
},
};
expect(async () => validateMaxContentLength(server, log)).not.to.throwError();
sinon.assert.notCalled(log);
expect(async () => validateMaxContentLength(server, logger.warning)).not.to.throwError();
sinon.assert.notCalled(logger.warning);
});
});

View file

@ -0,0 +1,31 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { ConfigObject, KbnServer, Logger } from '../../../types';
import { validateBrowser } from './validate_browser';
// @ts-ignore
import { validateConfig } from './validate_config';
import { validateMaxContentLength } from './validate_max_content_length';
export async function runValidations(
server: KbnServer,
config: ConfigObject,
logger: Logger,
browserFactory: any
) {
try {
await Promise.all([
validateBrowser(server, browserFactory, logger),
validateConfig(config, logger),
validateMaxContentLength(server, logger),
]);
logger.debug(`Reporting plugin self-check ok!`);
} catch (err) {
logger.warning(
`Reporting plugin self-check failed. Please check the Kibana Reporting settings. ${err}`
);
}
}

View file

@ -4,23 +4,27 @@
* you may not use this file except in compliance with the Elastic License.
*/
import * as puppeteer from 'puppeteer-core';
import { CHROMIUM } from '../browsers/browser_types';
import { KbnServer, Logger } from '../../../types';
import { CHROMIUM } from '../../browsers/browser_types';
export const validateBrowser = async (browserFactory: any, log: (message: string) => any) => {
/*
* Validate the Reporting headless browser can launch, and that it can connect
* to the locally running Kibana instance.
*/
export const validateBrowser = async (server: KbnServer, browserFactory: any, logger: Logger) => {
if (browserFactory.type === CHROMIUM) {
return browserFactory
.test(
{
viewport: {
width: 800,
height: 600,
},
viewport: { width: 800, height: 600 },
},
log
logger
)
.then((browser: puppeteer.Browser | null) => {
if (browser && browser.close) {
browser.close();
} else {
throw new Error('Could not close browser client handle!');
}
});
}

View file

@ -6,11 +6,13 @@
import crypto from 'crypto';
export function validateConfig(config, log) {
export function validateConfig(config, logger) {
const encryptionKey = config.get('xpack.reporting.encryptionKey');
if (encryptionKey === null || encryptionKey === undefined) {
log('Generating a random key for xpack.reporting.encryptionKey. To prevent pending reports from failing on ' +
'restart, please set xpack.reporting.encryptionKey in kibana.yml');
if (encryptionKey == null) {
logger.warning(
`Generating a random key for xpack.reporting.encryptionKey. To prevent pending reports from failing on restart, please set ` +
`xpack.reporting.encryptionKey in kibana.yml`
);
config.set('xpack.reporting.encryptionKey', crypto.randomBytes(16).toString('hex'));
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import numeral from '@elastic/numeral';
import { defaults, get } from 'lodash';
import { Logger } from '../../../types';
const KIBANA_MAX_SIZE_BYTES_PATH = 'xpack.reporting.csv.maxSizeBytes';
const ES_MAX_SIZE_BYTES_PATH = 'http.max_content_length';
export async function validateMaxContentLength(server: any, logger: Logger) {
const config = server.config();
const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('data');
const elasticClusterSettingsResponse = await callWithInternalUser('cluster.getSettings', {
includeDefaults: true,
});
const { persistent, transient, defaults: defaultSettings } = elasticClusterSettingsResponse;
const elasticClusterSettings = defaults({}, persistent, transient, defaultSettings);
const elasticSearchMaxContent = get(elasticClusterSettings, 'http.max_content_length', '100mb');
const elasticSearchMaxContentBytes = numeral().unformat(elasticSearchMaxContent.toUpperCase());
const kibanaMaxContentBytes = config.get(KIBANA_MAX_SIZE_BYTES_PATH);
if (kibanaMaxContentBytes > elasticSearchMaxContentBytes) {
logger.warning(
`${KIBANA_MAX_SIZE_BYTES_PATH} (${kibanaMaxContentBytes}) is higher than ElasticSearch's ${ES_MAX_SIZE_BYTES_PATH} (${elasticSearchMaxContentBytes}). ` +
`Please set ${ES_MAX_SIZE_BYTES_PATH} in ElasticSearch to match, or lower your ${KIBANA_MAX_SIZE_BYTES_PATH} in Kibana to avoid this warning.`
);
}
}

View file

@ -1,35 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import numeral from '@elastic/numeral';
import { defaults, get } from 'lodash';
const KIBANA_MAX_SIZE_BYTES_PATH = 'xpack.reporting.csv.maxSizeBytes';
const ES_MAX_SIZE_BYTES_PATH = 'http.max_content_length';
export async function validateMaxContentLength(server: any, log: (message: string) => any) {
const config = server.config();
const { callWithInternalUser } = server.plugins.elasticsearch.getCluster('data');
try {
const elasticClusterSettingsResponse = await callWithInternalUser('cluster.getSettings', {
includeDefaults: true,
});
const { persistent, transient, defaults: defaultSettings } = elasticClusterSettingsResponse;
const elasticClusterSettings = defaults({}, persistent, transient, defaultSettings);
const elasticSearchMaxContent = get(elasticClusterSettings, 'http.max_content_length', '100mb');
const elasticSearchMaxContentBytes = numeral().unformat(elasticSearchMaxContent.toUpperCase());
const kibanaMaxContentBytes = config.get(KIBANA_MAX_SIZE_BYTES_PATH);
if (kibanaMaxContentBytes > elasticSearchMaxContentBytes) {
log(
`${KIBANA_MAX_SIZE_BYTES_PATH} (${kibanaMaxContentBytes}) is higher than ElasticSearch's ${ES_MAX_SIZE_BYTES_PATH} (${elasticSearchMaxContentBytes}). ` +
`Please set ${ES_MAX_SIZE_BYTES_PATH} in ElasticSearch to match, or lower your ${KIBANA_MAX_SIZE_BYTES_PATH} in Kibana to avoid this warning.`
);
}
} catch (e) {
log(`Could not retrieve cluster settings, because of ${e.message}`);
}
}