From a7e189b40798cd12560c63a5e2d1bab6acbf87a0 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 30 Oct 2019 15:12:42 -0400 Subject: [PATCH 01/11] Initial work --- src/legacy/core_plugins/telemetry/index.ts | 26 ++++++++++++++++--- .../public/components/telemetry_form.js | 5 ++++ .../telemetry/server/get_telemetry_opt_in.ts | 6 +++++ .../core_plugins/telemetry/server/plugin.ts | 10 +++++-- .../telemetry/server/routes/index.ts | 12 +++++++-- 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index 4b6566415f3e1..fea0d89dd7df0 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -17,6 +17,7 @@ * under the License. */ +import * as Rx from 'rxjs'; import { resolve } from 'path'; import JoiNamespace from 'joi'; import { Server } from 'hapi'; @@ -45,6 +46,7 @@ const telemetry = (kibana: any) => { config(Joi: typeof JoiNamespace) { return Joi.object({ enabled: Joi.boolean().default(true), + alwaysOptedIn: Joi.boolean().default(false), // `config` is used internally and not intended to be set config: Joi.string().default(Joi.ref('$defaultConfigPath')), banner: Joi.boolean().default(true), @@ -80,8 +82,13 @@ const telemetry = (kibana: any) => { }, }, async replaceInjectedVars(originalInjectedVars: any, request: any) { + const alwaysOptedIn = request.server.config().get('telemetry.alwaysOptedIn'); const currentKibanaVersion = getCurrentKibanaVersion(request.server); - const telemetryOptedIn = await getTelemetryOptIn({ request, currentKibanaVersion }); + const telemetryOptedIn = await getTelemetryOptIn({ + alwaysOptedIn, + request, + currentKibanaVersion, + }); return { ...originalInjectedVars, @@ -91,6 +98,7 @@ const telemetry = (kibana: any) => { injectDefaultVars(server: Server) { const config = server.config(); return { + alwaysOptedIn: config.get('telemetry.alwaysOptedIn'), telemetryEnabled: getXpackConfigWithDeprecated(config, 'telemetry.enabled'), telemetryUrl: getXpackConfigWithDeprecated(config, 'telemetry.url'), telemetryBanner: getXpackConfigWithDeprecated(config, 'telemetry.banner'), @@ -100,13 +108,25 @@ const telemetry = (kibana: any) => { hacks: ['plugins/telemetry/hacks/telemetry_init', 'plugins/telemetry/hacks/telemetry_opt_in'], mappings, }, - init(server: Server) { + async init(server: Server) { const initializerContext = { env: { packageInfo: { version: getCurrentKibanaVersion(server), }, }, + config: { + create() { + const config = server.config(); + return Rx.of({ + enabled: config.get('telemetry.enabled'), + alwaysOptedIn: config.get('telemetry.alwaysOptedIn'), + config: config.get('telemetry.config'), + banner: config.get('telemetry.banner'), + url: config.get('telemetry.url'), + }); + }, + }, } as PluginInitializerContext; const coreSetup = ({ @@ -114,7 +134,7 @@ const telemetry = (kibana: any) => { log: server.log, } as any) as CoreSetup; - telemetryPlugin(initializerContext).setup(coreSetup); + await telemetryPlugin(initializerContext).setup(coreSetup); // register collectors server.usage.collectorSet.register(createLocalizationUsageCollector(server)); diff --git a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js index c2dcd48ee57da..1f09ec7526baa 100644 --- a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js +++ b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js @@ -17,6 +17,7 @@ * under the License. */ +import chrome from 'ui/chrome'; import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { @@ -69,6 +70,10 @@ export class TelemetryForm extends Component { } render() { + if (chrome.getInjected('alwaysOptedIn')) { + return null; + } + const { telemetryOptInProvider, } = this.props; diff --git a/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts b/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts index c8bd4a4b6dfbd..fb4b3278fff93 100644 --- a/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts +++ b/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts @@ -24,6 +24,7 @@ import { SavedObjectAttributes } from './routes/opt_in'; interface GetTelemetryOptIn { request: any; currentKibanaVersion: string; + alwaysOptedIn: boolean; } // Returns whether telemetry has been opt'ed into or not. @@ -31,6 +32,7 @@ interface GetTelemetryOptIn { export async function getTelemetryOptIn({ request, currentKibanaVersion, + alwaysOptedIn, }: GetTelemetryOptIn): Promise { const isRequestingApplication = request.path.startsWith('/app'); @@ -39,6 +41,10 @@ export async function getTelemetryOptIn({ return false; } + if (alwaysOptedIn) { + return true; + } + const savedObjectsClient = request.getSavedObjectsClient(); let savedObject; diff --git a/src/legacy/core_plugins/telemetry/server/plugin.ts b/src/legacy/core_plugins/telemetry/server/plugin.ts index a5f0f1234799a..773dedcd3f5c8 100644 --- a/src/legacy/core_plugins/telemetry/server/plugin.ts +++ b/src/legacy/core_plugins/telemetry/server/plugin.ts @@ -17,6 +17,8 @@ * under the License. */ +import { first } from 'rxjs/operators'; +import { Observable } from 'rxjs'; import { CoreSetup, PluginInitializerContext } from 'src/core/server'; import { registerRoutes } from './routes'; import { telemetryCollectionManager } from './collection_manager'; @@ -24,14 +26,18 @@ import { getStats } from './telemetry_collection'; export class TelemetryPlugin { private readonly currentKibanaVersion: string; + private readonly config$: Observable; constructor(initializerContext: PluginInitializerContext) { this.currentKibanaVersion = initializerContext.env.packageInfo.version; + this.config$ = initializerContext.config.create(); } - public setup(core: CoreSetup) { + public async setup(core: CoreSetup) { const currentKibanaVersion = this.currentKibanaVersion; telemetryCollectionManager.setStatsGetter(getStats, 'local'); - registerRoutes({ core, currentKibanaVersion }); + + const { alwaysOptedIn } = await this.config$.pipe(first()).toPromise(); + registerRoutes({ alwaysOptedIn, core, currentKibanaVersion }); } } diff --git a/src/legacy/core_plugins/telemetry/server/routes/index.ts b/src/legacy/core_plugins/telemetry/server/routes/index.ts index 2eb6bf95b4f45..426ac1188a3f0 100644 --- a/src/legacy/core_plugins/telemetry/server/routes/index.ts +++ b/src/legacy/core_plugins/telemetry/server/routes/index.ts @@ -24,9 +24,17 @@ import { registerTelemetryDataRoutes } from './telemetry_stats'; interface RegisterRoutesParams { core: CoreSetup; currentKibanaVersion: string; + alwaysOptedIn: boolean; } -export function registerRoutes({ core, currentKibanaVersion }: RegisterRoutesParams) { - registerOptInRoutes({ core, currentKibanaVersion }); +export function registerRoutes({ + alwaysOptedIn, + core, + currentKibanaVersion, +}: RegisterRoutesParams) { registerTelemetryDataRoutes(core); + + if (!alwaysOptedIn) { + registerOptInRoutes({ core, currentKibanaVersion }); + } } From 603075521bc160989a56874cf929158bd4859ee2 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 30 Oct 2019 16:56:46 -0400 Subject: [PATCH 02/11] WIP changes --- src/legacy/core_plugins/telemetry/index.ts | 12 ++++++------ .../telemetry/public/components/telemetry_form.js | 2 +- .../telemetry/server/get_telemetry_opt_in.ts | 6 ------ src/legacy/core_plugins/telemetry/server/plugin.ts | 4 ++-- .../core_plugins/telemetry/server/routes/index.ts | 6 +++--- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index fea0d89dd7df0..f1874e5ba6017 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -46,7 +46,8 @@ const telemetry = (kibana: any) => { config(Joi: typeof JoiNamespace) { return Joi.object({ enabled: Joi.boolean().default(true), - alwaysOptedIn: Joi.boolean().default(false), + optIn: Joi.boolean().default(null), + allowChangingOptInStatus: Joi.boolean().default(true), // `config` is used internally and not intended to be set config: Joi.string().default(Joi.ref('$defaultConfigPath')), banner: Joi.boolean().default(true), @@ -82,10 +83,8 @@ const telemetry = (kibana: any) => { }, }, async replaceInjectedVars(originalInjectedVars: any, request: any) { - const alwaysOptedIn = request.server.config().get('telemetry.alwaysOptedIn'); const currentKibanaVersion = getCurrentKibanaVersion(request.server); const telemetryOptedIn = await getTelemetryOptIn({ - alwaysOptedIn, request, currentKibanaVersion, }); @@ -98,11 +97,11 @@ const telemetry = (kibana: any) => { injectDefaultVars(server: Server) { const config = server.config(); return { - alwaysOptedIn: config.get('telemetry.alwaysOptedIn'), telemetryEnabled: getXpackConfigWithDeprecated(config, 'telemetry.enabled'), telemetryUrl: getXpackConfigWithDeprecated(config, 'telemetry.url'), telemetryBanner: getXpackConfigWithDeprecated(config, 'telemetry.banner'), - telemetryOptedIn: null, + telemetryOptedIn: config.get('telemetry.optIn'), + allowChangingOptInStatus: config.get('telemetry.allowChangingOptInStatus'), }; }, hacks: ['plugins/telemetry/hacks/telemetry_init', 'plugins/telemetry/hacks/telemetry_opt_in'], @@ -120,10 +119,11 @@ const telemetry = (kibana: any) => { const config = server.config(); return Rx.of({ enabled: config.get('telemetry.enabled'), - alwaysOptedIn: config.get('telemetry.alwaysOptedIn'), + optIn: config.get('telemetry.optIn'), config: config.get('telemetry.config'), banner: config.get('telemetry.banner'), url: config.get('telemetry.url'), + allowChangingOptInStatus: config.get('telemetry.allowChangingOptInStatus'), }); }, }, diff --git a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js index 1f09ec7526baa..c42f261368318 100644 --- a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js +++ b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js @@ -70,7 +70,7 @@ export class TelemetryForm extends Component { } render() { - if (chrome.getInjected('alwaysOptedIn')) { + if (chrome.getInjected('allowChangingOptInStatus')) { return null; } diff --git a/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts b/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts index fb4b3278fff93..c8bd4a4b6dfbd 100644 --- a/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts +++ b/src/legacy/core_plugins/telemetry/server/get_telemetry_opt_in.ts @@ -24,7 +24,6 @@ import { SavedObjectAttributes } from './routes/opt_in'; interface GetTelemetryOptIn { request: any; currentKibanaVersion: string; - alwaysOptedIn: boolean; } // Returns whether telemetry has been opt'ed into or not. @@ -32,7 +31,6 @@ interface GetTelemetryOptIn { export async function getTelemetryOptIn({ request, currentKibanaVersion, - alwaysOptedIn, }: GetTelemetryOptIn): Promise { const isRequestingApplication = request.path.startsWith('/app'); @@ -41,10 +39,6 @@ export async function getTelemetryOptIn({ return false; } - if (alwaysOptedIn) { - return true; - } - const savedObjectsClient = request.getSavedObjectsClient(); let savedObject; diff --git a/src/legacy/core_plugins/telemetry/server/plugin.ts b/src/legacy/core_plugins/telemetry/server/plugin.ts index 773dedcd3f5c8..b0c684526e2c6 100644 --- a/src/legacy/core_plugins/telemetry/server/plugin.ts +++ b/src/legacy/core_plugins/telemetry/server/plugin.ts @@ -37,7 +37,7 @@ export class TelemetryPlugin { const currentKibanaVersion = this.currentKibanaVersion; telemetryCollectionManager.setStatsGetter(getStats, 'local'); - const { alwaysOptedIn } = await this.config$.pipe(first()).toPromise(); - registerRoutes({ alwaysOptedIn, core, currentKibanaVersion }); + const { allowChangingOptInStatus } = await this.config$.pipe(first()).toPromise(); + registerRoutes({ allowChangingOptInStatus, core, currentKibanaVersion }); } } diff --git a/src/legacy/core_plugins/telemetry/server/routes/index.ts b/src/legacy/core_plugins/telemetry/server/routes/index.ts index 426ac1188a3f0..50e39ce9c4939 100644 --- a/src/legacy/core_plugins/telemetry/server/routes/index.ts +++ b/src/legacy/core_plugins/telemetry/server/routes/index.ts @@ -24,17 +24,17 @@ import { registerTelemetryDataRoutes } from './telemetry_stats'; interface RegisterRoutesParams { core: CoreSetup; currentKibanaVersion: string; - alwaysOptedIn: boolean; + allowChangingOptInStatus: boolean; } export function registerRoutes({ - alwaysOptedIn, + allowChangingOptInStatus, core, currentKibanaVersion, }: RegisterRoutesParams) { registerTelemetryDataRoutes(core); - if (!alwaysOptedIn) { + if (allowChangingOptInStatus) { registerOptInRoutes({ core, currentKibanaVersion }); } } From 9bf5ef363131fbb4ef0a6499580251e3da1e03dd Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 30 Oct 2019 17:10:01 -0400 Subject: [PATCH 03/11] Turn off banner when allowChangingOptInStatus is true --- src/legacy/core_plugins/telemetry/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index f1874e5ba6017..da6bed13255b7 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -99,7 +99,9 @@ const telemetry = (kibana: any) => { return { telemetryEnabled: getXpackConfigWithDeprecated(config, 'telemetry.enabled'), telemetryUrl: getXpackConfigWithDeprecated(config, 'telemetry.url'), - telemetryBanner: getXpackConfigWithDeprecated(config, 'telemetry.banner'), + telemetryBanner: + config.get('allowChangingOptInStatus') !== true && + getXpackConfigWithDeprecated(config, 'telemetry.banner'), telemetryOptedIn: config.get('telemetry.optIn'), allowChangingOptInStatus: config.get('telemetry.allowChangingOptInStatus'), }; From 838b9eb09235f242cdc6dc3df148b0042f9290c2 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 31 Oct 2019 11:55:36 -0400 Subject: [PATCH 04/11] Fix bugs --- src/legacy/core_plugins/telemetry/index.ts | 13 ++++++++++--- .../telemetry/public/components/telemetry_form.js | 2 +- .../telemetry/public/services/telemetry_opt_in.ts | 4 ++++ .../license_management/public/lib/telemetry.js | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index da6bed13255b7..cc97abc7151ab 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -46,7 +46,9 @@ const telemetry = (kibana: any) => { config(Joi: typeof JoiNamespace) { return Joi.object({ enabled: Joi.boolean().default(true), - optIn: Joi.boolean().default(null), + optIn: Joi.boolean() + .allow(null) + .default(null), allowChangingOptInStatus: Joi.boolean().default(true), // `config` is used internally and not intended to be set config: Joi.string().default(Joi.ref('$defaultConfigPath')), @@ -83,12 +85,17 @@ const telemetry = (kibana: any) => { }, }, async replaceInjectedVars(originalInjectedVars: any, request: any) { + const config = request.server.config(); const currentKibanaVersion = getCurrentKibanaVersion(request.server); - const telemetryOptedIn = await getTelemetryOptIn({ + let telemetryOptedIn = await getTelemetryOptIn({ request, currentKibanaVersion, }); + if (telemetryOptedIn == null) { + telemetryOptedIn = config.get('telemetry.optIn'); + } + return { ...originalInjectedVars, telemetryOptedIn, @@ -100,7 +107,7 @@ const telemetry = (kibana: any) => { telemetryEnabled: getXpackConfigWithDeprecated(config, 'telemetry.enabled'), telemetryUrl: getXpackConfigWithDeprecated(config, 'telemetry.url'), telemetryBanner: - config.get('allowChangingOptInStatus') !== true && + config.get('telemetry.allowChangingOptInStatus') !== false && getXpackConfigWithDeprecated(config, 'telemetry.banner'), telemetryOptedIn: config.get('telemetry.optIn'), allowChangingOptInStatus: config.get('telemetry.allowChangingOptInStatus'), diff --git a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js index c42f261368318..9148f149a1e11 100644 --- a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js +++ b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js @@ -70,7 +70,7 @@ export class TelemetryForm extends Component { } render() { - if (chrome.getInjected('allowChangingOptInStatus')) { + if (!chrome.getInjected('allowChangingOptInStatus')) { return null; } diff --git a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts index f4462ffea7a33..4d27bad352cd4 100644 --- a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts +++ b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.ts @@ -28,11 +28,15 @@ let currentOptInStatus = false; export function TelemetryOptInProvider($injector: any, chrome: any) { currentOptInStatus = npStart.core.injectedMetadata.getInjectedVar('telemetryOptedIn') as boolean; + const allowChangingOptInStatus = npStart.core.injectedMetadata.getInjectedVar( + 'allowChangingOptInStatus' + ) as boolean; setCanTrackUiMetrics(currentOptInStatus); const provider = { getBannerId: () => bannerId, getOptIn: () => currentOptInStatus, + canChangeOptInStatus: () => allowChangingOptInStatus, setBannerId(id: string) { bannerId = id; }, diff --git a/x-pack/legacy/plugins/license_management/public/lib/telemetry.js b/x-pack/legacy/plugins/license_management/public/lib/telemetry.js index bf8bed05aabed..61d0322227d8e 100644 --- a/x-pack/legacy/plugins/license_management/public/lib/telemetry.js +++ b/x-pack/legacy/plugins/license_management/public/lib/telemetry.js @@ -25,7 +25,7 @@ export const optInToTelemetry = async (enableTelemetry) => { await telemetryOptInService.setOptIn(enableTelemetry); }; export const shouldShowTelemetryOptIn = () => { - return telemetryEnabled && !telemetryOptInService.getOptIn(); + return telemetryEnabled && !telemetryOptInService.getOptIn() && telemetryOptInService.canChangeOptInStatus(); }; export const getTelemetryFetcher = () => { return fetchTelemetry(httpClient, { unencrypted: true }); From 41124d69c8578c1bed2cbc503e1b5ece0ca22a84 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 31 Oct 2019 15:32:25 -0400 Subject: [PATCH 05/11] Fix broken jest tests --- .../telemetry/public/components/telemetry_form.js | 9 ++++----- .../telemetry/public/components/telemetry_form.test.js | 6 +++++- .../public/hacks/welcome_banner/click_banner.test.js | 6 +++--- .../hacks/welcome_banner/handle_old_settings.test.js | 2 +- .../hacks/welcome_banner/should_show_banner.test.js | 2 +- .../telemetry/public/services/telemetry_opt_in.test.js | 2 +- .../public/services/telemetry_opt_in.test.mocks.js | 3 ++- 7 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js index 9148f149a1e11..80eb2da59c47e 100644 --- a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js +++ b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.js @@ -17,7 +17,6 @@ * under the License. */ -import chrome from 'ui/chrome'; import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { @@ -70,10 +69,6 @@ export class TelemetryForm extends Component { } render() { - if (!chrome.getInjected('allowChangingOptInStatus')) { - return null; - } - const { telemetryOptInProvider, } = this.props; @@ -83,6 +78,10 @@ export class TelemetryForm extends Component { queryMatches, } = this.state; + if (!telemetryOptInProvider.canChangeOptInStatus()) { + return null; + } + if (queryMatches !== null && !queryMatches) { return null; } diff --git a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.test.js b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.test.js index 4d2c1dec27176..d15e285db1f52 100644 --- a/src/legacy/core_plugins/telemetry/public/components/telemetry_form.test.js +++ b/src/legacy/core_plugins/telemetry/public/components/telemetry_form.test.js @@ -17,7 +17,7 @@ * under the License. */ -import '../services/telemetry_opt_in.test.mocks'; +import { mockInjectedMetadata } from '../services/telemetry_opt_in.test.mocks'; import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import { TelemetryForm } from './telemetry_form'; @@ -33,6 +33,8 @@ const buildTelemetryOptInProvider = () => { switch (key) { case '$http': return mockHttp; + case 'allowChangingOptInStatus': + return true; default: return null; } @@ -48,6 +50,8 @@ const buildTelemetryOptInProvider = () => { describe('TelemetryForm', () => { it('renders as expected', () => { + mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: true }); + expect(shallowWithIntl( { const optIn = true; const bannerId = 'bruce-banner'; - mockInjectedMetadata({ telemetryOptedIn: optIn }); + mockInjectedMetadata({ telemetryOptedIn: optIn, allowChangingOptInStatus: true }); const telemetryOptInProvider = getTelemetryOptInProvider(); telemetryOptInProvider.setBannerId(bannerId); @@ -92,7 +92,7 @@ describe('click_banner', () => { remove: sinon.spy() }; const optIn = true; - mockInjectedMetadata({ telemetryOptedIn: null }); + mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: true }); const telemetryOptInProvider = getTelemetryOptInProvider({ simulateFailure: true }); await clickBanner(telemetryOptInProvider, optIn, { _banners: banners, _toastNotifications: toastNotifications }); @@ -110,7 +110,7 @@ describe('click_banner', () => { remove: sinon.spy() }; const optIn = false; - mockInjectedMetadata({ telemetryOptedIn: null }); + mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: true }); const telemetryOptInProvider = getTelemetryOptInProvider({ simulateError: true }); await clickBanner(telemetryOptInProvider, optIn, { _banners: banners, _toastNotifications: toastNotifications }); diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.test.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.test.js index fd21a5122b594..f26ca0ca0e3c5 100644 --- a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.test.js +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/handle_old_settings.test.js @@ -38,7 +38,7 @@ const getTelemetryOptInProvider = (enabled, { simulateFailure = false } = {}) => const chrome = { addBasePath: url => url }; - mockInjectedMetadata({ telemetryOptedIn: enabled }); + mockInjectedMetadata({ telemetryOptedIn: enabled, allowChangingOptInStatus: true }); const $injector = { get: (key) => { diff --git a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_banner.test.js b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_banner.test.js index 19e7ccbe61866..240c991a75b64 100644 --- a/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_banner.test.js +++ b/src/legacy/core_plugins/telemetry/public/hacks/welcome_banner/should_show_banner.test.js @@ -38,7 +38,7 @@ const getMockInjector = () => { }; const getTelemetryOptInProvider = ({ telemetryOptedIn = null } = {}) => { - mockInjectedMetadata({ telemetryOptedIn }); + mockInjectedMetadata({ telemetryOptedIn, allowChangingOptInStatus: true }); const injector = getMockInjector(); const chrome = { addBasePath: (url) => url diff --git a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.js b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.js index 0034fa4438238..26f14fc87d937 100644 --- a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.js +++ b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.js @@ -34,7 +34,7 @@ describe('TelemetryOptInProvider', () => { addBasePath: (url) => url }; - mockInjectedMetadata({ telemetryOptedIn: optedIn }); + mockInjectedMetadata({ telemetryOptedIn: optedIn, allowChangingOptInStatus: true }); const mockInjector = { get: (key) => { diff --git a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.mocks.js b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.mocks.js index f98f5e16e00c3..012f8de640042 100644 --- a/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.mocks.js +++ b/src/legacy/core_plugins/telemetry/public/services/telemetry_opt_in.test.mocks.js @@ -24,10 +24,11 @@ import { } from '../../../../../core/public/mocks'; const injectedMetadataMock = injectedMetadataServiceMock.createStartContract(); -export function mockInjectedMetadata({ telemetryOptedIn }) { +export function mockInjectedMetadata({ telemetryOptedIn, allowChangingOptInStatus }) { const mockGetInjectedVar = jest.fn().mockImplementation((key) => { switch (key) { case 'telemetryOptedIn': return telemetryOptedIn; + case 'allowChangingOptInStatus': return allowChangingOptInStatus; default: throw new Error(`unexpected injectedVar ${key}`); } }); From 51ddabee4747afb2b2382f29a330def7a2e6d93b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 31 Oct 2019 15:38:45 -0400 Subject: [PATCH 06/11] Add jest tests for TelemetryForm --- .../__snapshots__/telemetry_form.test.js.snap | 4 +++- .../public/components/telemetry_form.test.js | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap index c1ad6276aee25..e1aead3798de7 100644 --- a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap +++ b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap @@ -1,6 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TelemetryForm renders as expected 1`] = ` +exports[`TelemetryForm doesn't render form when not allowed to change optIn status 1`] = `""`; + +exports[`TelemetryForm renders as expected when allows to change optIn status 1`] = ` { }; describe('TelemetryForm', () => { - it('renders as expected', () => { + it('renders as expected when allows to change optIn status', () => { mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: true }); expect(shallowWithIntl( @@ -62,4 +62,18 @@ describe('TelemetryForm', () => { />) ).toMatchSnapshot(); }); + + it(`doesn't render form when not allowed to change optIn status`, () => { + mockInjectedMetadata({ telemetryOptedIn: null, allowChangingOptInStatus: false }); + + expect(shallowWithIntl( + ) + ).toMatchSnapshot(); + }); }); From fafa1a2ce08000b8ed8db3018d756e6e24a24d5b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 31 Oct 2019 17:01:06 -0400 Subject: [PATCH 07/11] Add TelemetryOptIn jest tests --- .../telemetry_opt_in.test.js.snap | 363 +++++++++++++++++- .../__jest__/telemetry_opt_in.test.js | 23 +- 2 files changed, 381 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/telemetry_opt_in.test.js.snap b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/telemetry_opt_in.test.js.snap index 642b8399ff6d1..f82e8b03527c0 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/telemetry_opt_in.test.js.snap +++ b/x-pack/legacy/plugins/license_management/__jest__/__snapshots__/telemetry_opt_in.test.js.snap @@ -104,7 +104,261 @@ exports[`TelemetryOptIn should display when telemetry not opted in 1`] = ` "timeZone": null, } } -/> +> + +
+ + +

+ + Help Elastic support provide better service + +

+
+ +
+ + + + + + } + className="eui-AlignBaseline" + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + id="readMorePopover" + isOpen={false} + ownFocus={true} + panelPaddingSize="m" + > + +

+ + + , + "telemetryPrivacyStatementLink": + + , + } + } + /> +

+
+ , + } + } + /> + + } + onChange={[Function]} + > +
+ +
+ +
+ + `; exports[`TelemetryOptIn should not display when telemetry is opted in 1`] = ` @@ -213,3 +467,110 @@ exports[`TelemetryOptIn should not display when telemetry is opted in 1`] = ` } /> `; + +exports[`TelemetryOptIn shouldn't display when telemetry optIn status can't change 1`] = ` + +`; diff --git a/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js b/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js index 4e94657e03dee..a92ca384e8a37 100644 --- a/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js +++ b/x-pack/legacy/plugins/license_management/__jest__/telemetry_opt_in.test.js @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; +import { setTelemetryEnabled, setTelemetryOptInService } from '../public/lib/telemetry'; import { TelemetryOptIn } from '../public/components/telemetry_opt_in'; import { mountWithIntl } from '../../../../test_utils/enzyme_helpers'; @@ -11,16 +12,30 @@ jest.mock('ui/capabilities', () => ({ get: jest.fn(), })); +setTelemetryEnabled(true); + describe('TelemetryOptIn', () => { test('should display when telemetry not opted in', () => { - const telemetry = require('../public/lib/telemetry'); - telemetry.showTelemetryOptIn = () => { return true; }; + setTelemetryOptInService({ + getOptIn: () => false, + canChangeOptInStatus: () => true, + }); const rendered = mountWithIntl(); expect(rendered).toMatchSnapshot(); }); test('should not display when telemetry is opted in', () => { - const telemetry = require('../public/lib/telemetry'); - telemetry.showTelemetryOptIn = () => { return false; }; + setTelemetryOptInService({ + getOptIn: () => true, + canChangeOptInStatus: () => true, + }); + const rendered = mountWithIntl(); + expect(rendered).toMatchSnapshot(); + }); + test(`shouldn't display when telemetry optIn status can't change`, () => { + setTelemetryOptInService({ + getOptIn: () => false, + canChangeOptInStatus: () => false, + }); const rendered = mountWithIntl(); expect(rendered).toMatchSnapshot(); }); From f7fa39d23d8856a26919b2412280c75ba8e344c1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 1 Nov 2019 10:46:06 -0400 Subject: [PATCH 08/11] Make some adjustments to allow always being opted in --- src/legacy/core_plugins/telemetry/index.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index cc97abc7151ab..5dc218f9f1441 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -86,14 +86,23 @@ const telemetry = (kibana: any) => { }, async replaceInjectedVars(originalInjectedVars: any, request: any) { const config = request.server.config(); + const optIn = config.get('telemetry.optIn'); + const allowChangingOptInStatus = config.get('telemetry.allowChangingOptInStatus'); const currentKibanaVersion = getCurrentKibanaVersion(request.server); - let telemetryOptedIn = await getTelemetryOptIn({ - request, - currentKibanaVersion, - }); + let telemetryOptedIn: boolean | null; - if (telemetryOptedIn == null) { - telemetryOptedIn = config.get('telemetry.optIn'); + if (typeof optIn === 'boolean' && !allowChangingOptInStatus) { + // When not allowed to change optIn status and an optIn value is set, we'll overwrite with that + telemetryOptedIn = optIn; + } else { + telemetryOptedIn = await getTelemetryOptIn({ + request, + currentKibanaVersion, + }); + if (telemetryOptedIn === null) { + // In the senario there's no value set in telemetryOptedIn, we'll return optIn value + telemetryOptedIn = optIn; + } } return { From 3faab04d1844b5832810318f75afc60747f03a06 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 11 Nov 2019 13:45:52 -0500 Subject: [PATCH 09/11] Disallow turning telemetry completely off --- src/legacy/core_plugins/telemetry/index.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index 5dc218f9f1441..9df2c9a99f0a7 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -65,7 +65,17 @@ const telemetry = (kibana: any) => { `https://telemetry.elastic.co/xpack/${ENDPOINT_VERSION}/send` ), }), - }).default(); + }) + .when( + Joi.object({ + optIn: Joi.valid(null).valid(false), + allowChangingOptInStatus: false, + }).unknown(), + { + then: Joi.object({ allowChangingOptInStatus: Joi.invalid(false) }), + } + ) + .default(); }, uiExports: { managementSections: ['plugins/telemetry/views/management'], From 9c523b934e29ede914076845b8d2a637a108f18c Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 11 Nov 2019 16:12:39 -0500 Subject: [PATCH 10/11] Fix bug in Joi config --- src/legacy/core_plugins/telemetry/index.ts | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/index.ts b/src/legacy/core_plugins/telemetry/index.ts index 9df2c9a99f0a7..50a25423b5eb8 100644 --- a/src/legacy/core_plugins/telemetry/index.ts +++ b/src/legacy/core_plugins/telemetry/index.ts @@ -46,9 +46,13 @@ const telemetry = (kibana: any) => { config(Joi: typeof JoiNamespace) { return Joi.object({ enabled: Joi.boolean().default(true), - optIn: Joi.boolean() - .allow(null) - .default(null), + optIn: Joi.when('allowChangingOptInStatus', { + is: false, + then: Joi.valid(true), + otherwise: Joi.boolean() + .allow(null) + .default(null), + }), allowChangingOptInStatus: Joi.boolean().default(true), // `config` is used internally and not intended to be set config: Joi.string().default(Joi.ref('$defaultConfigPath')), @@ -65,17 +69,7 @@ const telemetry = (kibana: any) => { `https://telemetry.elastic.co/xpack/${ENDPOINT_VERSION}/send` ), }), - }) - .when( - Joi.object({ - optIn: Joi.valid(null).valid(false), - allowChangingOptInStatus: false, - }).unknown(), - { - then: Joi.object({ allowChangingOptInStatus: Joi.invalid(false) }), - } - ) - .default(); + }).default(); }, uiExports: { managementSections: ['plugins/telemetry/views/management'], From 573436176678400c8a76484655099b1c97cdeab4 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 11 Nov 2019 17:03:43 -0500 Subject: [PATCH 11/11] Keep route there --- src/legacy/core_plugins/telemetry/server/plugin.ts | 8 +------- .../core_plugins/telemetry/server/routes/index.ts | 12 ++---------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/server/plugin.ts b/src/legacy/core_plugins/telemetry/server/plugin.ts index b0c684526e2c6..813aa0df09e8c 100644 --- a/src/legacy/core_plugins/telemetry/server/plugin.ts +++ b/src/legacy/core_plugins/telemetry/server/plugin.ts @@ -17,8 +17,6 @@ * under the License. */ -import { first } from 'rxjs/operators'; -import { Observable } from 'rxjs'; import { CoreSetup, PluginInitializerContext } from 'src/core/server'; import { registerRoutes } from './routes'; import { telemetryCollectionManager } from './collection_manager'; @@ -26,18 +24,14 @@ import { getStats } from './telemetry_collection'; export class TelemetryPlugin { private readonly currentKibanaVersion: string; - private readonly config$: Observable; constructor(initializerContext: PluginInitializerContext) { this.currentKibanaVersion = initializerContext.env.packageInfo.version; - this.config$ = initializerContext.config.create(); } public async setup(core: CoreSetup) { const currentKibanaVersion = this.currentKibanaVersion; telemetryCollectionManager.setStatsGetter(getStats, 'local'); - - const { allowChangingOptInStatus } = await this.config$.pipe(first()).toPromise(); - registerRoutes({ allowChangingOptInStatus, core, currentKibanaVersion }); + registerRoutes({ core, currentKibanaVersion }); } } diff --git a/src/legacy/core_plugins/telemetry/server/routes/index.ts b/src/legacy/core_plugins/telemetry/server/routes/index.ts index 50e39ce9c4939..549b3ef6068ec 100644 --- a/src/legacy/core_plugins/telemetry/server/routes/index.ts +++ b/src/legacy/core_plugins/telemetry/server/routes/index.ts @@ -24,17 +24,9 @@ import { registerTelemetryDataRoutes } from './telemetry_stats'; interface RegisterRoutesParams { core: CoreSetup; currentKibanaVersion: string; - allowChangingOptInStatus: boolean; } -export function registerRoutes({ - allowChangingOptInStatus, - core, - currentKibanaVersion, -}: RegisterRoutesParams) { +export function registerRoutes({ core, currentKibanaVersion }: RegisterRoutesParams) { registerTelemetryDataRoutes(core); - - if (allowChangingOptInStatus) { - registerOptInRoutes({ core, currentKibanaVersion }); - } + registerOptInRoutes({ core, currentKibanaVersion }); }