From 803523d029f5fa50cfeb565e28b81b34c3276901 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Wed, 16 Oct 2024 17:26:37 -0700 Subject: [PATCH] Implement similar surfacing mechanisms as for deprecated routes --- .../src/routes/resolve_deprecated_api.ts | 16 +++++-- .../src/http_server.ts | 40 ++++++++++++++++ .../src/http_service.ts | 1 + .../core-http-server-internal/src/types.ts | 7 +++ packages/core/http/core-http-server/index.ts | 1 + .../core-http-server/src/http_contract.ts | 9 ++++ .../core-http-server/src/router/router.ts | 8 ++++ .../core-http-server/src/versioning/types.ts | 8 +++- .../src/plugin_context.ts | 1 + .../src/usage_stats_client.ts | 7 +++ .../src/core_usage_data_service.ts | 16 ++++++- .../src/core_usage_stats_client.ts | 48 ++++++++++++++++++- .../core-usage-data-server/index.ts | 1 + .../src/core_usage_stats.ts | 13 +++++ .../core-usage-data-server/src/index.ts | 6 ++- .../src/setup_contract.ts | 14 +++++- .../kibana_usage_collection/server/plugin.ts | 7 +++ 17 files changed, 194 insertions(+), 9 deletions(-) diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/routes/resolve_deprecated_api.ts b/packages/core/deprecations/core-deprecations-server-internal/src/routes/resolve_deprecated_api.ts index c087d94920041..6da8585c93b19 100644 --- a/packages/core/deprecations/core-deprecations-server-internal/src/routes/resolve_deprecated_api.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/routes/resolve_deprecated_api.ts @@ -10,8 +10,11 @@ import { schema } from '@kbn/config-schema'; import { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { InternalDeprecationRouter } from '../internal_types'; -import { buildApiDeprecationId } from '../deprecations'; - +import { + buildApiDeprecationId, + // buildRestrictedApiId, +} from '../deprecations'; +// refactor to reuse for restrictedApiRequests export const registerMarkAsResolvedRoute = ( router: InternalDeprecationRouter, { coreUsageData }: { coreUsageData: InternalCoreUsageDataSetup } @@ -44,8 +47,15 @@ export const registerMarkAsResolvedRoute = ( routePath, routeVersion, }); - + /* + const counterName = buildRestrictedApiId({ + routeMethod, + routePath, + routeVersion, + }); + */ await usageClient.incrementDeprecatedApi(counterName, { resolved: true, incrementBy }); + // await usageClient.incrementRestrictedApi(counterName, { resolved: true, incrementBy }); return res.ok(); } ); diff --git a/packages/core/http/core-http-server-internal/src/http_server.ts b/packages/core/http/core-http-server-internal/src/http_server.ts index 17617ea9bdd64..4b02187083a74 100644 --- a/packages/core/http/core-http-server-internal/src/http_server.ts +++ b/packages/core/http/core-http-server-internal/src/http_server.ts @@ -427,6 +427,46 @@ export class HttpServer { return deprecatedRoutes; } + /* + private getRestrictedRoutes(): RouterRestrictedRouteDetails[] { + const restrictedRoutes: RouterRestrictedRouteDetails[] = []; + + for (const router of this.registeredRouters) { + const allRouterRoutes = [ + // exclude so we dont get double entries. + // we need to call the versioned getRoutes to grab the full version options details + router.getRoutes({ excludeVersionedRoutes: true }), + router.versioned.getRoutes(), + ].flat(); + + restrictedRoutes.push( + ...allRouterRoutes + .flat() + .map((route) => { + if (route.isVersioned === true) { + return [...route.handlers.entries()].map(([version, { options }]) => { + const restricted = options.options?.access === 'internal'; // here we're diverging a bit from how deprecated is implemented + return { route, version: `${version}`, restricted }; + }); + } + return { route, version: undefined, restricted: route.options.access === 'internel' }; + }) + .flat() + .filter(({ restricted }) => isObject(restricted)) + .flatMap(({ route, restricted, version }) => { + return { + routeRestrictedOptions: restricted!, + routeMethod: route.method as RouteMethod, + routePath: route.path, + routeVersion: version, + }; + }) + ); + } + + return restrictedRoutes; + } + */ private setupGracefulShutdownHandlers() { this.registerOnPreRouting((request, response, toolkit) => { diff --git a/packages/core/http/core-http-server-internal/src/http_service.ts b/packages/core/http/core-http-server-internal/src/http_service.ts index af310a6792057..d0c887e0d84d4 100644 --- a/packages/core/http/core-http-server-internal/src/http_service.ts +++ b/packages/core/http/core-http-server-internal/src/http_service.ts @@ -189,6 +189,7 @@ export class HttpService Router.on('onPostValidate', cb); }, getRegisteredDeprecatedApis: () => serverContract.getDeprecatedRoutes(), + // getRegisteredRestrictedApis: () => serverContract.getRestrictedRoutes(), externalUrl: new ExternalUrlConfig(config.externalUrl), createRouter: ( path: string, diff --git a/packages/core/http/core-http-server-internal/src/types.ts b/packages/core/http/core-http-server-internal/src/types.ts index 0706af9ad73a2..2023b1dd9f526 100644 --- a/packages/core/http/core-http-server-internal/src/types.ts +++ b/packages/core/http/core-http-server-internal/src/types.ts @@ -17,9 +17,11 @@ import type { HttpServiceSetup, HttpServiceStart, RouterDeprecatedRouteDetails, + // RouterRestrictedRouteDetails, } from '@kbn/core-http-server'; import { CoreKibanaRequest } from '@kbn/core-http-router-server-internal'; import { RouteDeprecationInfo } from '@kbn/core-http-server/src/router/route'; +// import { RouteRestrictedInfo } from '@kbn/core-http-server/src/router/route'; import type { HttpServerSetup } from './http_server'; import type { ExternalUrlConfig } from './external_url'; import type { InternalStaticAssets } from './static_assets'; @@ -57,6 +59,10 @@ export interface InternalHttpServiceSetup path: string, plugin?: PluginOpaqueId ) => IRouter; + // not sure yet if we can combine deprecations and restrictions + // registerOnPostValidation( + // cb: (req: CoreKibanaRequest, metadata: { deprecated: RouteDeprecationInfo, restricted: RouteRestrictedInfo }) => void + // ): void; registerOnPostValidation( cb: (req: CoreKibanaRequest, metadata: { deprecated: RouteDeprecationInfo }) => void ): void; @@ -72,6 +78,7 @@ export interface InternalHttpServiceSetup provider: IContextProvider ) => IContextContainer; getRegisteredDeprecatedApis: () => RouterDeprecatedRouteDetails[]; + // getRegisteredRestrictedApis: () => RouterRestrictedRouteDetails[]; } /** @internal */ diff --git a/packages/core/http/core-http-server/index.ts b/packages/core/http/core-http-server/index.ts index 7fe125c6aa9a7..151a54a69351d 100644 --- a/packages/core/http/core-http-server/index.ts +++ b/packages/core/http/core-http-server/index.ts @@ -94,6 +94,7 @@ export type { RouteRegistrar, RouterRoute, RouterDeprecatedRouteDetails, + // RouterRestrictedRouteDetails, IKibanaSocket, KibanaErrorResponseFactory, KibanaRedirectionResponseFactory, diff --git a/packages/core/http/core-http-server/src/http_contract.ts b/packages/core/http/core-http-server/src/http_contract.ts index e2f675bd8d0c0..fc692f18b8d7e 100644 --- a/packages/core/http/core-http-server/src/http_contract.ts +++ b/packages/core/http/core-http-server/src/http_contract.ts @@ -13,6 +13,7 @@ import type { IRouter, RequestHandlerContextBase, RouterDeprecatedRouteDetails, + // RouterRestrictedRouteDetails, } from './router'; import type { AuthenticationHandler, @@ -368,6 +369,14 @@ export interface HttpServiceSetup< * @returns {RouterDeprecatedRouteDetails[]} */ getDeprecatedRoutes: () => RouterDeprecatedRouteDetails[]; + + // /** + // * Provides a list of all registered restricted routes {{@link RouterRestrictedRouteDetails | information}}. + // * The routers will be evaluated everytime this function gets called to + // * accommodate for any late route registrations + // * @returns {RouterRestrictedRouteDetails[]} + // */ + // getRestrictedRoutes: () => RouterRestrictedRouteDetails[]; } /** @public */ diff --git a/packages/core/http/core-http-server/src/router/router.ts b/packages/core/http/core-http-server/src/router/router.ts index d8b79bee13025..4426edff3431d 100644 --- a/packages/core/http/core-http-server/src/router/router.ts +++ b/packages/core/http/core-http-server/src/router/router.ts @@ -149,3 +149,11 @@ export interface RouterDeprecatedRouteDetails { routePath: string; routeVersion?: string; } +// I'm not sure if I need this, TBD +// /** @public */ +// export interface RouterRestrictedRouteDetails { +// routeRestrictedOptions: RouteRestrictedInfo; +// routeMethod: RouteMethod; +// routePath: string; +// routeVersion?: string; +// } diff --git a/packages/core/http/core-http-server/src/versioning/types.ts b/packages/core/http/core-http-server/src/versioning/types.ts index 05b81a57bf86d..2a2420dd95e83 100644 --- a/packages/core/http/core-http-server/src/versioning/types.ts +++ b/packages/core/http/core-http-server/src/versioning/types.ts @@ -73,7 +73,13 @@ export type VersionedRouteConfig = Omit< * ``` */ summary?: string; - + /** + * Declares this operation to be deprecated. Consumers SHOULD refrain from usage + * of this route. This will be surfaced in OAS documentation. + * + * @default false + */ + deprecated?: boolean; /** * Optional API description, which supports [CommonMark](https://spec.commonmark.org) markdown formatting * diff --git a/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts index 795047a61fb93..1fb00c39555eb 100644 --- a/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts +++ b/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts @@ -284,6 +284,7 @@ export function createPluginSetupContext({ coreUsageData: { registerUsageCounter: deps.coreUsageData.registerUsageCounter, registerDeprecatedUsageFetch: deps.coreUsageData.registerDeprecatedUsageFetch, + // registerRestrictedUsageFetch: deps.coreUsageData.registerRestrictedUsageFetch, }, plugins: { onSetup: (...dependencyNames) => runtimeResolver.onSetup(plugin.name, dependencyNames), diff --git a/packages/core/usage-data/core-usage-data-base-server-internal/src/usage_stats_client.ts b/packages/core/usage-data/core-usage-data-base-server-internal/src/usage_stats_client.ts index 044fb683fb69a..d547f560009d2 100644 --- a/packages/core/usage-data/core-usage-data-base-server-internal/src/usage_stats_client.ts +++ b/packages/core/usage-data/core-usage-data-base-server-internal/src/usage_stats_client.ts @@ -44,7 +44,14 @@ export interface ICoreUsageStatsClient { counterName: string, options: { resolved?: boolean; incrementBy?: number } ): Promise; + /* + getRestrictedApiUsageStats(): Promise; + incrementRestrictedApi( + counterName: string, + options: { resolved?: boolean; incrementBy?: number } + ): Promise; +*/ incrementSavedObjectsBulkCreate(options: BaseIncrementOptions): Promise; incrementSavedObjectsBulkGet(options: BaseIncrementOptions): Promise; diff --git a/packages/core/usage-data/core-usage-data-server-internal/src/core_usage_data_service.ts b/packages/core/usage-data/core-usage-data-server-internal/src/core_usage_data_service.ts index b1117934348e7..2d2c098acca5e 100644 --- a/packages/core/usage-data/core-usage-data-server-internal/src/core_usage_data_service.ts +++ b/packages/core/usage-data/core-usage-data-server-internal/src/core_usage_data_service.ts @@ -49,7 +49,10 @@ import { } from '@kbn/core-saved-objects-server'; import { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; -import { DeprecatedApiUsageFetcher } from '@kbn/core-usage-data-server/src/setup_contract'; +import { + DeprecatedApiUsageFetcher, + // RestrictedApiUsageFetcher, +} from '@kbn/core-usage-data-server/src/setup_contract'; import { isConfigured } from './is_configured'; import { coreUsageStatsType } from './saved_objects'; import { CoreUsageStatsClient } from './core_usage_stats_client'; @@ -91,6 +94,7 @@ export class CoreUsageDataService private deprecatedConfigPaths: ChangedDeprecatedPaths = { set: [], unset: [] }; private incrementUsageCounter: CoreIncrementUsageCounter = () => {}; // Initially set to noop private deprecatedApiUsageFetcher: DeprecatedApiUsageFetcher = async () => []; // Initially set to noop + // private restrictedApiUsageFetcher: RestrictedApiUsageFetcher = async () => []; // Initially set to noop constructor(core: CoreContext) { this.logger = core.logger.get('core-usage-stats-service'); @@ -524,6 +528,14 @@ export class CoreUsageDataService return this.deprecatedApiUsageFetcher(params); }; + // const registerRestrictedUsageFetch = (fetchFn: RestrictedApiUsageFetcher) => { + // this.restrictedApiUsageFetcher = fetchFn; + // }; + + // const fetchRestrictedUsageStats = (params: { soClient: ISavedObjectsRepository }) => { + // return this.restrictedApiUsageFetcher(params); + // }; + this.coreUsageStatsClient = new CoreUsageStatsClient({ debugLogger: (message: string) => this.logger.debug(message), basePath: http.basePath, @@ -531,6 +543,7 @@ export class CoreUsageDataService stop$: this.stop$, incrementUsageCounter, fetchDeprecatedUsageStats, + // fetchRestrictedUsageStats, }); const contract: InternalCoreUsageDataSetup = { @@ -539,6 +552,7 @@ export class CoreUsageDataService registerUsageCounter, incrementUsageCounter, registerDeprecatedUsageFetch, + // registerRestrictedUsageFetch, }; return contract; diff --git a/packages/core/usage-data/core-usage-data-server-internal/src/core_usage_stats_client.ts b/packages/core/usage-data/core-usage-data-server-internal/src/core_usage_stats_client.ts index c7a4134b35dbf..97055a85a98ff 100644 --- a/packages/core/usage-data/core-usage-data-server-internal/src/core_usage_stats_client.ts +++ b/packages/core/usage-data/core-usage-data-server-internal/src/core_usage_stats_client.ts @@ -37,7 +37,10 @@ import { takeUntil, tap, } from 'rxjs'; -import { DeprecatedApiUsageFetcher } from '@kbn/core-usage-data-server/src/setup_contract'; +import { + DeprecatedApiUsageFetcher, + // RestrictedApiUsafeFetcher, +} from '@kbn/core-usage-data-server/src/setup_contract'; export const BULK_CREATE_STATS_PREFIX = 'apiCalls.savedObjectsBulkCreate'; export const BULK_GET_STATS_PREFIX = 'apiCalls.savedObjectsBulkGet'; @@ -119,6 +122,15 @@ export interface CoreUsageDeprecatedApiEvent { incrementBy: number; } +// /** +// * Interface that models some of the core events (e.g. SO HTTP API calls) +// * @internal +// */ +// export interface CoreUsageRestrictedApiEvent { +// id: string; +// resolved: boolean; +// incrementBy: number; +// } /** @internal */ export interface CoreUsageStatsClientParams { debugLogger: (message: string) => void; @@ -128,6 +140,7 @@ export interface CoreUsageStatsClientParams { incrementUsageCounter: (params: CoreIncrementCounterParams) => void; bufferTimeMs?: number; fetchDeprecatedUsageStats: DeprecatedApiUsageFetcher; + // fetchRestrictedUsageStats: RestrictedApiUsageFetcher; } /** @internal */ @@ -140,6 +153,8 @@ export class CoreUsageStatsClient implements ICoreUsageStatsClient { private readonly coreUsageEvents$ = new Subject(); private readonly coreUsageDeprecatedApiCalls$ = new Subject(); private readonly fetchDeprecatedUsageStats: DeprecatedApiUsageFetcher; + // private readonly coreUsageRestrictedApiCalls$ = new Subject(); + // private readonly fetchRestrictedUsageStats: RestrictedApiUsageFetcher; constructor({ debugLogger, @@ -149,11 +164,13 @@ export class CoreUsageStatsClient implements ICoreUsageStatsClient { incrementUsageCounter, bufferTimeMs = DEFAULT_BUFFER_TIME_MS, fetchDeprecatedUsageStats, - }: CoreUsageStatsClientParams) { + }: // fetchRestrictedUsageStats + CoreUsageStatsClientParams) { this.debugLogger = debugLogger; this.basePath = basePath; this.repositoryPromise = repositoryPromise; this.fetchDeprecatedUsageStats = fetchDeprecatedUsageStats; + // this.fetchRestrictedUsageStats = fetchRestrictedUsageStats this.fieldsToIncrement$ .pipe( takeUntil(stop$), @@ -209,6 +226,19 @@ export class CoreUsageStatsClient implements ICoreUsageStatsClient { ) .subscribe(); + // this.coreUsageRestrictedApiCalls$ + // .pipe( + // takeUntil(stop$), + // tap(({ id, incrementBy, resolved }) => { + // incrementUsageCounter({ + // counterName: id, + // counterType: `restricted_api_call:${resolved ? 'resolved' : 'total'}`, + // incrementBy, + // }); + // }) + // ) + // .subscribe(); + this.coreUsageEvents$ .pipe( takeUntil(stop$), @@ -258,6 +288,20 @@ export class CoreUsageStatsClient implements ICoreUsageStatsClient { return await this.fetchDeprecatedUsageStats({ soClient: repository }); } + // public async incrementRestrictedApi( + // id: string, + // { resolved = false, incrementBy = 1 }: { resolved: boolean; incrementBy: number } + // ) { + // const restrictedField = resolved ? 'restricted_api_calls_resolved' : 'restricted_api_calls'; + // this.coreUsageRestrictedApiCalls$.next({ id, resolved, incrementBy }); + // this.fieldsToIncrement$.next([`${restrictedField}.total`]); + // } + + // public async getRestrictedApiUsageStats() { + // const repository = await this.repositoryPromise; + // return await this.fetchRestrictedUsageStats({ soClient: repository }); + // } + public async incrementSavedObjectsBulkCreate(options: BaseIncrementOptions) { await this.updateUsageStats([], BULK_CREATE_STATS_PREFIX, options); } diff --git a/packages/core/usage-data/core-usage-data-server/index.ts b/packages/core/usage-data/core-usage-data-server/index.ts index 77221ec937ab0..492f79e3cc498 100644 --- a/packages/core/usage-data/core-usage-data-server/index.ts +++ b/packages/core/usage-data/core-usage-data-server/index.ts @@ -20,4 +20,5 @@ export type { CoreServicesUsageData, CoreUsageStats, CoreDeprecatedApiUsageStats, + // CoreRestrictedApiUsageStats, } from './src'; diff --git a/packages/core/usage-data/core-usage-data-server/src/core_usage_stats.ts b/packages/core/usage-data/core-usage-data-server/src/core_usage_stats.ts index 39df9d30d19c9..3b0f58f689c5a 100644 --- a/packages/core/usage-data/core-usage-data-server/src/core_usage_stats.ts +++ b/packages/core/usage-data/core-usage-data-server/src/core_usage_stats.ts @@ -159,3 +159,16 @@ export interface CoreDeprecatedApiUsageStats { apiTotalCalls: number; apiLastCalledAt: string; } + +/** + * @public + * + * CoreRestrictedApiCounterStats are collected over time while Kibana is running. + */ +// export interface CoreRestrictedApiCounterStats { +// apiId: string; +// totalMarkedAsResolved: number; +// markedAsResolvedLastCalledAt: string; +// apiTotalCalls: number; +// apiLastCalledAt: string; +// } diff --git a/packages/core/usage-data/core-usage-data-server/src/index.ts b/packages/core/usage-data/core-usage-data-server/src/index.ts index 5d4bbcfc64bbc..dfca246c65d53 100644 --- a/packages/core/usage-data/core-usage-data-server/src/index.ts +++ b/packages/core/usage-data/core-usage-data-server/src/index.ts @@ -12,7 +12,11 @@ export type { CoreEnvironmentUsageData, CoreConfigUsageData, } from './core_usage_data'; -export type { CoreUsageStats, CoreDeprecatedApiUsageStats } from './core_usage_stats'; +export type { + CoreUsageStats, + CoreDeprecatedApiUsageStats, + // CoreRestrictedApiUsageStats, +} from './core_usage_stats'; export type { CoreUsageDataSetup, CoreUsageCounter, diff --git a/packages/core/usage-data/core-usage-data-server/src/setup_contract.ts b/packages/core/usage-data/core-usage-data-server/src/setup_contract.ts index 30ed7edb6ce1d..94c5f37f33541 100644 --- a/packages/core/usage-data/core-usage-data-server/src/setup_contract.ts +++ b/packages/core/usage-data/core-usage-data-server/src/setup_contract.ts @@ -8,7 +8,10 @@ */ import type { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; -import type { CoreDeprecatedApiUsageStats } from './core_usage_stats'; +import type { + CoreDeprecatedApiUsageStats, + // CoreRestrictedApiCounterStats, +} from './core_usage_stats'; /** * Internal API for registering the Usage Tracker used for Core's usage data payload. @@ -22,6 +25,7 @@ export interface CoreUsageDataSetup { */ registerUsageCounter: (usageCounter: CoreUsageCounter) => void; registerDeprecatedUsageFetch: (fetchFn: DeprecatedApiUsageFetcher) => void; + // registerRestrictedUsageFetch: (fetchFn: RestrictedApiUsageFetcher) => void; } /** @@ -58,3 +62,11 @@ export type CoreIncrementUsageCounter = (params: CoreIncrementCounterParams) => export type DeprecatedApiUsageFetcher = (params: { soClient: ISavedObjectsRepository; }) => Promise; + +// /** +// * @public +// * Registers the restricted API fetcher to be called to grab all the restricted API usage details. +// */ +// export type RestrictedApiUsageFetcher = (params: { +// soClient: ISavedObjectsRepository; +// }) => Promise; diff --git a/src/plugins/kibana_usage_collection/server/plugin.ts b/src/plugins/kibana_usage_collection/server/plugin.ts index 48fb1c6ff7b9b..33eb7628d1310 100644 --- a/src/plugins/kibana_usage_collection/server/plugin.ts +++ b/src/plugins/kibana_usage_collection/server/plugin.ts @@ -44,6 +44,7 @@ import { registerSavedObjectsCountUsageCollector, registerEventLoopDelaysCollector, fetchDeprecatedApiCounterStats, + // fetchRestrictedApiCounterStats } from './collectors'; interface KibanaUsageCollectionPluginsDepsSetup { @@ -78,7 +79,13 @@ export class KibanaUsageCollectionPlugin implements Plugin { const deprecatedUsageFetch = fetchDeprecatedApiCounterStats( this.logger.get('deprecated-api-usage') ); + /* + const restrictedUsageFetch = fetchRestrictedApiCounterStats( + this.logger.get('restricted-api-usage') + ); + */ coreSetup.coreUsageData.registerDeprecatedUsageFetch(deprecatedUsageFetch); + // coreSetup.coreUsageData.registerRestrictedUsageFetch(RestrictedUsageFetch); this.registerUsageCollectors( usageCollection, coreSetup,