mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
# Backport This will backport the following commits from `main` to `8.14`: - [[HTTP/OAS] HTTP API (#181144)](https://github.com/elastic/kibana/pull/181144) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Jean-Louis Leysens","email":"jeanlouis.leysens@elastic.co"},"sourceCommit":{"committedDate":"2024-04-19T13:07:35Z","message":"[HTTP/OAS] HTTP API (#181144)\n\n## Summary\r\n\r\nAdds a new core-owned experimental HTTP API: `GET /api/oas` with the\r\nfollowing query params for filtering:\r\n\r\n- `pluginId` - request a specific plugin's OAS\r\n- `pathStartsWith` - request OAS for paths that start with the given\r\nstring\r\n\r\nThe current rationale is that this will provide sufficient scoping to\r\nallow developers and docs maintainers to request only the OAS they need\r\n(since Kibana's surface area is HUGE).\r\n\r\nAlso added a new experimental config: `server.oas.enabled: <boolean>`.\r\nSet this to `true` to play around with this feature locally.\r\n\r\n## How to test\r\n\r\n1. Add `server.oas.enabled: true` to `kibana.dev.yml`\r\n2. Start Kibana with `yarn start --no-base-path`\r\n3. `curl -uelastic:changeme\r\nhttp://localhost:5601/api/oas\\?pathStartsWith\\=/api/status | jq`\r\n4. You should have a JSON representation of an OAS doc containing the\r\n`/api/status` endpoint!\r\n\r\n<details>\r\n\r\n<summary>example</summary>\r\n\r\n```json\r\n{\r\n \"openapi\": \"3.0.0\",\r\n \"info\": {\r\n \"title\": \"Kibana HTTP APIs\",\r\n \"version\": \"0.0.0\"\r\n },\r\n \"servers\": [\r\n {\r\n \"url\": \"http://localhost:5601\"\r\n }\r\n ],\r\n \"paths\": {\r\n \"/api/status\": {\r\n \"get\": {\r\n \"responses\": {},\r\n \"parameters\": [\r\n {\r\n \"in\": \"header\",\r\n \"name\": \"elastic-api-version\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"enum\": [\r\n \"2023-10-31\"\r\n ],\r\n \"default\": \"2023-10-31\"\r\n }\r\n },\r\n {\r\n \"name\": \"v7format\",\r\n \"in\": \"query\",\r\n \"required\": false,\r\n \"schema\": {\r\n \"type\": \"boolean\"\r\n }\r\n },\r\n {\r\n \"name\": \"v8format\",\r\n \"in\": \"query\",\r\n \"required\": false,\r\n \"schema\": {\r\n \"type\": \"boolean\"\r\n }\r\n }\r\n ],\r\n \"operationId\": \"/api/status#0\"\r\n }\r\n }\r\n },\r\n \"components\": {\r\n \"schemas\": {},\r\n \"securitySchemes\": {\r\n \"basicAuth\": {\r\n \"type\": \"http\",\r\n \"scheme\": \"basic\"\r\n },\r\n \"apiKeyAuth\": {\r\n \"type\": \"apiKey\",\r\n \"in\": \"header\",\r\n \"name\": \"Authorization\"\r\n }\r\n }\r\n },\r\n \"security\": [\r\n {\r\n \"basicAuth\": []\r\n }\r\n ]\r\n}\r\n\r\n```\r\n\r\n</details>\r\n\r\n## Risks\r\n\r\n* The work to generate OAS can be expensive (for both CPU and memory).\r\nTo mitigate, the endpoint will only be registered provided a specific\r\nconfig and we are using concurrency control (`Semaphore`) to allow only\r\none of these operations to be handled at a time.\r\n\r\n## Future work\r\n\r\n* We must start the long tail work of furnishing endpoints with missing\r\nresponse schemas. I intend to do so for the `/api/status` route next\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"654c0dc467784d0c71d7c20e409136c9e10a1e3c","branchLabelMapping":{"^v8.15.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:http","Team:Core","release_note:skip","Team:obs-ux-infra_services","apm:review","v8.14.0","v8.15.0"],"title":"[HTTP/OAS] HTTP API `/api/oas`","number":181144,"url":"https://github.com/elastic/kibana/pull/181144","mergeCommit":{"message":"[HTTP/OAS] HTTP API (#181144)\n\n## Summary\r\n\r\nAdds a new core-owned experimental HTTP API: `GET /api/oas` with the\r\nfollowing query params for filtering:\r\n\r\n- `pluginId` - request a specific plugin's OAS\r\n- `pathStartsWith` - request OAS for paths that start with the given\r\nstring\r\n\r\nThe current rationale is that this will provide sufficient scoping to\r\nallow developers and docs maintainers to request only the OAS they need\r\n(since Kibana's surface area is HUGE).\r\n\r\nAlso added a new experimental config: `server.oas.enabled: <boolean>`.\r\nSet this to `true` to play around with this feature locally.\r\n\r\n## How to test\r\n\r\n1. Add `server.oas.enabled: true` to `kibana.dev.yml`\r\n2. Start Kibana with `yarn start --no-base-path`\r\n3. `curl -uelastic:changeme\r\nhttp://localhost:5601/api/oas\\?pathStartsWith\\=/api/status | jq`\r\n4. You should have a JSON representation of an OAS doc containing the\r\n`/api/status` endpoint!\r\n\r\n<details>\r\n\r\n<summary>example</summary>\r\n\r\n```json\r\n{\r\n \"openapi\": \"3.0.0\",\r\n \"info\": {\r\n \"title\": \"Kibana HTTP APIs\",\r\n \"version\": \"0.0.0\"\r\n },\r\n \"servers\": [\r\n {\r\n \"url\": \"http://localhost:5601\"\r\n }\r\n ],\r\n \"paths\": {\r\n \"/api/status\": {\r\n \"get\": {\r\n \"responses\": {},\r\n \"parameters\": [\r\n {\r\n \"in\": \"header\",\r\n \"name\": \"elastic-api-version\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"enum\": [\r\n \"2023-10-31\"\r\n ],\r\n \"default\": \"2023-10-31\"\r\n }\r\n },\r\n {\r\n \"name\": \"v7format\",\r\n \"in\": \"query\",\r\n \"required\": false,\r\n \"schema\": {\r\n \"type\": \"boolean\"\r\n }\r\n },\r\n {\r\n \"name\": \"v8format\",\r\n \"in\": \"query\",\r\n \"required\": false,\r\n \"schema\": {\r\n \"type\": \"boolean\"\r\n }\r\n }\r\n ],\r\n \"operationId\": \"/api/status#0\"\r\n }\r\n }\r\n },\r\n \"components\": {\r\n \"schemas\": {},\r\n \"securitySchemes\": {\r\n \"basicAuth\": {\r\n \"type\": \"http\",\r\n \"scheme\": \"basic\"\r\n },\r\n \"apiKeyAuth\": {\r\n \"type\": \"apiKey\",\r\n \"in\": \"header\",\r\n \"name\": \"Authorization\"\r\n }\r\n }\r\n },\r\n \"security\": [\r\n {\r\n \"basicAuth\": []\r\n }\r\n ]\r\n}\r\n\r\n```\r\n\r\n</details>\r\n\r\n## Risks\r\n\r\n* The work to generate OAS can be expensive (for both CPU and memory).\r\nTo mitigate, the endpoint will only be registered provided a specific\r\nconfig and we are using concurrency control (`Semaphore`) to allow only\r\none of these operations to be handled at a time.\r\n\r\n## Future work\r\n\r\n* We must start the long tail work of furnishing endpoints with missing\r\nresponse schemas. I intend to do so for the `/api/status` route next\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"654c0dc467784d0c71d7c20e409136c9e10a1e3c"}},"sourceBranch":"main","suggestedTargetBranches":["8.14"],"targetPullRequestStates":[{"branch":"8.14","label":"v8.14.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.15.0","branchLabelMappingKey":"^v8.15.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/181144","number":181144,"mergeCommit":{"message":"[HTTP/OAS] HTTP API (#181144)\n\n## Summary\r\n\r\nAdds a new core-owned experimental HTTP API: `GET /api/oas` with the\r\nfollowing query params for filtering:\r\n\r\n- `pluginId` - request a specific plugin's OAS\r\n- `pathStartsWith` - request OAS for paths that start with the given\r\nstring\r\n\r\nThe current rationale is that this will provide sufficient scoping to\r\nallow developers and docs maintainers to request only the OAS they need\r\n(since Kibana's surface area is HUGE).\r\n\r\nAlso added a new experimental config: `server.oas.enabled: <boolean>`.\r\nSet this to `true` to play around with this feature locally.\r\n\r\n## How to test\r\n\r\n1. Add `server.oas.enabled: true` to `kibana.dev.yml`\r\n2. Start Kibana with `yarn start --no-base-path`\r\n3. `curl -uelastic:changeme\r\nhttp://localhost:5601/api/oas\\?pathStartsWith\\=/api/status | jq`\r\n4. You should have a JSON representation of an OAS doc containing the\r\n`/api/status` endpoint!\r\n\r\n<details>\r\n\r\n<summary>example</summary>\r\n\r\n```json\r\n{\r\n \"openapi\": \"3.0.0\",\r\n \"info\": {\r\n \"title\": \"Kibana HTTP APIs\",\r\n \"version\": \"0.0.0\"\r\n },\r\n \"servers\": [\r\n {\r\n \"url\": \"http://localhost:5601\"\r\n }\r\n ],\r\n \"paths\": {\r\n \"/api/status\": {\r\n \"get\": {\r\n \"responses\": {},\r\n \"parameters\": [\r\n {\r\n \"in\": \"header\",\r\n \"name\": \"elastic-api-version\",\r\n \"schema\": {\r\n \"type\": \"string\",\r\n \"enum\": [\r\n \"2023-10-31\"\r\n ],\r\n \"default\": \"2023-10-31\"\r\n }\r\n },\r\n {\r\n \"name\": \"v7format\",\r\n \"in\": \"query\",\r\n \"required\": false,\r\n \"schema\": {\r\n \"type\": \"boolean\"\r\n }\r\n },\r\n {\r\n \"name\": \"v8format\",\r\n \"in\": \"query\",\r\n \"required\": false,\r\n \"schema\": {\r\n \"type\": \"boolean\"\r\n }\r\n }\r\n ],\r\n \"operationId\": \"/api/status#0\"\r\n }\r\n }\r\n },\r\n \"components\": {\r\n \"schemas\": {},\r\n \"securitySchemes\": {\r\n \"basicAuth\": {\r\n \"type\": \"http\",\r\n \"scheme\": \"basic\"\r\n },\r\n \"apiKeyAuth\": {\r\n \"type\": \"apiKey\",\r\n \"in\": \"header\",\r\n \"name\": \"Authorization\"\r\n }\r\n }\r\n },\r\n \"security\": [\r\n {\r\n \"basicAuth\": []\r\n }\r\n ]\r\n}\r\n\r\n```\r\n\r\n</details>\r\n\r\n## Risks\r\n\r\n* The work to generate OAS can be expensive (for both CPU and memory).\r\nTo mitigate, the endpoint will only be registered provided a specific\r\nconfig and we are using concurrency control (`Semaphore`) to allow only\r\none of these operations to be handled at a time.\r\n\r\n## Future work\r\n\r\n* We must start the long tail work of furnishing endpoints with missing\r\nresponse schemas. I intend to do so for the `/api/status` route next\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"654c0dc467784d0c71d7c20e409136c9e10a1e3c"}}]}] BACKPORT--> Co-authored-by: Jean-Louis Leysens <jeanlouis.leysens@elastic.co>
This commit is contained in:
parent
963727c1c5
commit
e65ee683e5
36 changed files with 424 additions and 100 deletions
|
@ -135,6 +135,12 @@ describe('Router', () => {
|
|||
expect(lazyValidation).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('registers pluginId if provided', () => {
|
||||
const pluginId = Symbol('test');
|
||||
const router = new Router('', logger, enhanceWithContext, { pluginId });
|
||||
expect(router.pluginId).toBe(pluginId);
|
||||
});
|
||||
|
||||
describe('Options', () => {
|
||||
it('throws if validation for a route is not defined explicitly', () => {
|
||||
const router = new Router('', logger, enhanceWithContext, routerOptions);
|
||||
|
|
|
@ -125,6 +125,9 @@ export interface RouterOptions {
|
|||
/** Whether we are running in development */
|
||||
isDev?: boolean;
|
||||
|
||||
/** Plugin for which this router was registered */
|
||||
pluginId?: symbol;
|
||||
|
||||
versionedRouterOptions?: {
|
||||
/** {@inheritdoc VersionedRouterArgs['defaultHandlerResolutionStrategy'] }*/
|
||||
defaultHandlerResolutionStrategy?: 'newest' | 'oldest' | 'none';
|
||||
|
@ -163,6 +166,7 @@ export class Router<Context extends RequestHandlerContextBase = RequestHandlerCo
|
|||
implements IRouter<Context>
|
||||
{
|
||||
public routes: Array<Readonly<InternalRouterRoute>> = [];
|
||||
public pluginId?: symbol;
|
||||
public get: InternalRegistrar<'get', Context>;
|
||||
public post: InternalRegistrar<'post', Context>;
|
||||
public delete: InternalRegistrar<'delete', Context>;
|
||||
|
@ -175,6 +179,7 @@ export class Router<Context extends RequestHandlerContextBase = RequestHandlerCo
|
|||
private readonly enhanceWithContext: ContextEnhancer<any, any, any, any, any>,
|
||||
private readonly options: RouterOptions
|
||||
) {
|
||||
this.pluginId = options.pluginId;
|
||||
const buildMethod =
|
||||
<Method extends RouteMethod>(method: Method) =>
|
||||
<P, Q, B>(
|
||||
|
|
|
@ -24,6 +24,12 @@ describe('Versioned router', () => {
|
|||
expect(versionedRouter.getRoutes()).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('registers pluginId if router has one', () => {
|
||||
const pluginId = Symbol('test');
|
||||
const versionedRouter = CoreVersionedRouter.from({ router: createRouter({ pluginId }) });
|
||||
expect(versionedRouter.pluginId).toBe(pluginId);
|
||||
});
|
||||
|
||||
it('provides the expected metadata', () => {
|
||||
const versionedRouter = CoreVersionedRouter.from({ router });
|
||||
versionedRouter.get({ path: '/test/{id}', access: 'internal' });
|
||||
|
|
|
@ -43,6 +43,7 @@ export interface VersionedRouterArgs {
|
|||
export class CoreVersionedRouter implements VersionedRouter {
|
||||
private readonly routes = new Set<CoreVersionedRoute>();
|
||||
public readonly useVersionResolutionStrategyForInternalPaths: Map<string, boolean> = new Map();
|
||||
public pluginId?: symbol;
|
||||
public static from({
|
||||
router,
|
||||
defaultHandlerResolutionStrategy,
|
||||
|
@ -62,6 +63,7 @@ export class CoreVersionedRouter implements VersionedRouter {
|
|||
public readonly isDev: boolean = false,
|
||||
useVersionResolutionStrategyForInternalPaths: string[] = []
|
||||
) {
|
||||
this.pluginId = this.router.pluginId;
|
||||
for (const path of useVersionResolutionStrategyForInternalPaths) {
|
||||
this.useVersionResolutionStrategyForInternalPaths.set(path, true);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
|
||||
import { Router } from '../router';
|
||||
|
||||
export function createRouter() {
|
||||
interface CreateMockRouterOptions {
|
||||
pluginId?: symbol;
|
||||
}
|
||||
export function createRouter(opts: CreateMockRouterOptions = {}) {
|
||||
return {
|
||||
delete: jest.fn(),
|
||||
get: jest.fn(),
|
||||
|
@ -19,5 +22,6 @@ export function createRouter() {
|
|||
patch: jest.fn(),
|
||||
routerPath: '',
|
||||
versioned: {} as any,
|
||||
pluginId: opts.pluginId,
|
||||
} as unknown as jest.Mocked<Router>;
|
||||
}
|
||||
|
|
|
@ -73,6 +73,9 @@ Object {
|
|||
"valueInBytes": 1048576,
|
||||
},
|
||||
"name": "kibana-hostname",
|
||||
"oas": Object {
|
||||
"enabled": false,
|
||||
},
|
||||
"payloadTimeout": 20000,
|
||||
"port": 5601,
|
||||
"requestId": Object {
|
||||
|
|
|
@ -494,6 +494,11 @@ describe('cors', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('oas is disabled by default', () => {
|
||||
const { oas } = config.schema.validate({});
|
||||
expect(oas.enabled).toBe(false);
|
||||
});
|
||||
|
||||
describe('versioned', () => {
|
||||
it('defaults version resolution "oldest" not in dev', () => {
|
||||
expect(config.schema.validate({}, { dev: undefined })).toMatchObject({
|
||||
|
|
|
@ -46,7 +46,7 @@ const validHostName = () => {
|
|||
* We assume the URL does not contain anything after the pathname so that
|
||||
* we can safely append values to the pathname at runtime.
|
||||
*/
|
||||
function validateCdnURL(urlString: string): undefined | string {
|
||||
export const validateCdnURL = (urlString: string) => {
|
||||
const cdnURL = new URL(urlString);
|
||||
const errors: string[] = [];
|
||||
if (cdnURL.hash.length) {
|
||||
|
@ -58,7 +58,7 @@ function validateCdnURL(urlString: string): undefined | string {
|
|||
if (errors.length) {
|
||||
return `CDN URL "${cdnURL.href}" is invalid:${EOL}${errors.join(EOL)}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const configSchema = schema.object(
|
||||
{
|
||||
|
@ -82,6 +82,9 @@ const configSchema = schema.object(
|
|||
cdn: schema.object({
|
||||
url: schema.maybe(schema.uri({ scheme: ['http', 'https'], validate: validateCdnURL })),
|
||||
}),
|
||||
oas: schema.object({
|
||||
enabled: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
cors: schema.object(
|
||||
{
|
||||
enabled: schema.boolean({ defaultValue: false }),
|
||||
|
@ -290,6 +293,9 @@ export class HttpConfig implements IHttpConfig {
|
|||
allowCredentials: boolean;
|
||||
allowOrigin: string[];
|
||||
};
|
||||
public oas: {
|
||||
enabled: boolean;
|
||||
};
|
||||
public securityResponseHeaders: Record<string, string | string[]>;
|
||||
public customResponseHeaders: Record<string, string | string[]>;
|
||||
public maxPayload: ByteSizeValue;
|
||||
|
@ -363,6 +369,7 @@ export class HttpConfig implements IHttpConfig {
|
|||
this.restrictInternalApis = rawHttpConfig.restrictInternalApis ?? false;
|
||||
this.eluMonitor = rawHttpConfig.eluMonitor;
|
||||
this.versioned = rawHttpConfig.versioned;
|
||||
this.oas = rawHttpConfig.oas;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,14 +19,13 @@ import {
|
|||
} from '@kbn/server-http-tools';
|
||||
|
||||
import type { Duration } from 'moment';
|
||||
import { firstValueFrom, Observable, Subscription } from 'rxjs';
|
||||
import { take, pairwise } from 'rxjs';
|
||||
import { Observable, Subscription, firstValueFrom, pairwise, take } from 'rxjs';
|
||||
import apm from 'elastic-apm-node';
|
||||
// @ts-expect-error no type definition
|
||||
import Brok from 'brok';
|
||||
import type { Logger, LoggerFactory } from '@kbn/logging';
|
||||
import type { InternalExecutionContextSetup } from '@kbn/core-execution-context-server-internal';
|
||||
import { isSafeMethod } from '@kbn/core-http-router-server-internal';
|
||||
import { CoreVersionedRouter, isSafeMethod, Router } from '@kbn/core-http-router-server-internal';
|
||||
import type {
|
||||
IRouter,
|
||||
RouteConfigOptions,
|
||||
|
@ -168,6 +167,11 @@ export interface HttpServerSetupOptions {
|
|||
executionContext?: InternalExecutionContextSetup;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface GetRoutersOptions {
|
||||
pluginId?: string;
|
||||
}
|
||||
|
||||
export class HttpServer {
|
||||
private server?: Server;
|
||||
private config?: HttpConfig;
|
||||
|
@ -624,6 +628,38 @@ export class HttpServer {
|
|||
});
|
||||
}
|
||||
|
||||
public getRouters({ pluginId }: GetRoutersOptions = {}): {
|
||||
routers: Router[];
|
||||
versionedRouters: CoreVersionedRouter[];
|
||||
} {
|
||||
const routers: {
|
||||
routers: Router[];
|
||||
versionedRouters: CoreVersionedRouter[];
|
||||
} = {
|
||||
routers: [],
|
||||
versionedRouters: [],
|
||||
};
|
||||
const pluginIdFilter = pluginId ? Symbol(pluginId).toString() : undefined;
|
||||
|
||||
for (const router of this.registeredRouters) {
|
||||
const matchesIdFilter =
|
||||
!pluginIdFilter || (router as Router).pluginId?.toString() === pluginIdFilter;
|
||||
|
||||
if (
|
||||
matchesIdFilter &&
|
||||
(router as Router).getRoutes({ excludeVersionedRoutes: true }).length > 0
|
||||
) {
|
||||
routers.routers.push(router as Router);
|
||||
}
|
||||
|
||||
const versionedRouter = router.versioned as CoreVersionedRouter;
|
||||
if (matchesIdFilter && versionedRouter.getRoutes().length > 0) {
|
||||
routers.versionedRouters.push(versionedRouter);
|
||||
}
|
||||
}
|
||||
return routers;
|
||||
}
|
||||
|
||||
private registerStaticDir(path: string, dirPath: string) {
|
||||
if (this.server === undefined) {
|
||||
throw new Error('Http server is not setup up yet');
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Observable, Subscription, combineLatest, firstValueFrom } from 'rxjs';
|
||||
import { Observable, Subscription, combineLatest, firstValueFrom, of, mergeMap } from 'rxjs';
|
||||
import { map } from 'rxjs';
|
||||
import { pick } from '@kbn/std';
|
||||
|
||||
import { pick, Semaphore } from '@kbn/std';
|
||||
import { generateOpenApiDocument } from '@kbn/router-to-openapispec';
|
||||
import { Logger } from '@kbn/logging';
|
||||
import { Env } from '@kbn/config';
|
||||
import type { CoreContext, CoreService } from '@kbn/core-base-server-internal';
|
||||
|
@ -52,6 +53,7 @@ export interface SetupDeps {
|
|||
export class HttpService
|
||||
implements CoreService<InternalHttpServiceSetup, InternalHttpServiceStart>
|
||||
{
|
||||
private static readonly generateOasSemaphore = new Semaphore(1);
|
||||
private readonly prebootServer: HttpServer;
|
||||
private isPrebootServerStopped = false;
|
||||
private readonly httpServer: HttpServer;
|
||||
|
@ -182,6 +184,7 @@ export class HttpService
|
|||
const router = new Router<Context>(path, this.log, enhanceHandler, {
|
||||
isDev: this.env.mode.dev,
|
||||
versionedRouterOptions: getVersionedRouterOptions(config),
|
||||
pluginId,
|
||||
});
|
||||
registerRouter(router);
|
||||
return router;
|
||||
|
@ -222,12 +225,65 @@ export class HttpService
|
|||
await this.httpsRedirectServer.start(config);
|
||||
}
|
||||
|
||||
if (config.oas.enabled) {
|
||||
this.log.info('Registering experimental OAS API');
|
||||
this.registerOasApi(config);
|
||||
}
|
||||
|
||||
await this.httpServer.start();
|
||||
}
|
||||
|
||||
return this.getStartContract();
|
||||
}
|
||||
|
||||
private registerOasApi(config: HttpConfig) {
|
||||
const basePath = this.internalSetup?.basePath;
|
||||
const server = this.internalSetup?.server;
|
||||
if (!basePath || !server) {
|
||||
throw new Error('Cannot register OAS API before server setup is complete');
|
||||
}
|
||||
|
||||
const baseUrl =
|
||||
basePath.publicBaseUrl ?? `http://localhost:${config.port}${basePath.serverBasePath}`;
|
||||
|
||||
server.route({
|
||||
path: '/api/oas',
|
||||
method: 'GET',
|
||||
handler: async (req, h) => {
|
||||
const pathStartsWith = req.query?.pathStartsWith;
|
||||
const pluginId = req.query?.pluginId;
|
||||
return await firstValueFrom(
|
||||
of(1).pipe(
|
||||
HttpService.generateOasSemaphore.acquire(),
|
||||
mergeMap(async () => {
|
||||
try {
|
||||
// Potentially quite expensive
|
||||
const result = generateOpenApiDocument(this.httpServer.getRouters({ pluginId }), {
|
||||
baseUrl,
|
||||
title: 'Kibana HTTP APIs',
|
||||
version: '0.0.0', // TODO get a better version here
|
||||
pathStartsWith,
|
||||
});
|
||||
return h.response(result);
|
||||
} catch (e) {
|
||||
this.log.error(e);
|
||||
return h.response({ message: e.message }).code(500);
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
options: {
|
||||
app: { access: 'public' },
|
||||
auth: false,
|
||||
cache: {
|
||||
privacy: 'public',
|
||||
otherwise: 'must-revalidate',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if http server is configured to start listening on a configured port.
|
||||
* (if `server.autoListen` is not explicitly set to `false`.)
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
"@kbn/core-execution-context-server-mocks",
|
||||
"@kbn/core-http-context-server-mocks",
|
||||
"@kbn/logging-mocks",
|
||||
"@kbn/router-to-openapispec",
|
||||
"@kbn/core-base-server-mocks",
|
||||
],
|
||||
"exclude": [
|
||||
|
|
|
@ -17,4 +17,4 @@ export type {
|
|||
InternalHttpServiceSetupMock,
|
||||
InternalHttpServiceStartMock,
|
||||
} from './src/http_service.mock';
|
||||
export { createCoreContext, createHttpServer, createConfigService } from './src/test_utils';
|
||||
export { createCoreContext, createHttpService, createConfigService } from './src/test_utils';
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
type ExternalUrlConfigType,
|
||||
type CspConfigType,
|
||||
HttpService,
|
||||
config,
|
||||
} from '@kbn/core-http-server-internal';
|
||||
|
||||
const coreId = Symbol('core');
|
||||
|
@ -38,38 +39,43 @@ export const createConfigService = ({
|
|||
const configService = configServiceMock.create();
|
||||
configService.atPath.mockImplementation((path) => {
|
||||
if (path === 'server') {
|
||||
return new BehaviorSubject({
|
||||
name: 'kibana',
|
||||
hosts: ['localhost'],
|
||||
maxPayload: new ByteSizeValue(1024),
|
||||
autoListen: true,
|
||||
ssl: {
|
||||
enabled: false,
|
||||
},
|
||||
cors: {
|
||||
enabled: false,
|
||||
},
|
||||
compression: { enabled: true, brotli: { enabled: false } },
|
||||
xsrf: {
|
||||
disableProtection: true,
|
||||
allowlist: [],
|
||||
},
|
||||
securityResponseHeaders: {},
|
||||
customResponseHeaders: {},
|
||||
requestId: {
|
||||
allowFromAnyIp: true,
|
||||
ipAllowlist: [],
|
||||
},
|
||||
shutdownTimeout: moment.duration(30, 'seconds'),
|
||||
keepaliveTimeout: 120_000,
|
||||
socketTimeout: 120_000,
|
||||
restrictInternalApis: false,
|
||||
versioned: {
|
||||
versionResolution: 'oldest',
|
||||
strictClientVersionCheck: true,
|
||||
},
|
||||
...server,
|
||||
} as any);
|
||||
return new BehaviorSubject(
|
||||
Object.assign(
|
||||
config.schema.validate({}),
|
||||
{
|
||||
name: 'kibana',
|
||||
hosts: ['localhost'],
|
||||
maxPayload: new ByteSizeValue(1024),
|
||||
autoListen: true,
|
||||
ssl: {
|
||||
enabled: false,
|
||||
},
|
||||
cors: {
|
||||
enabled: false,
|
||||
},
|
||||
compression: { enabled: true, brotli: { enabled: false } },
|
||||
xsrf: {
|
||||
disableProtection: true,
|
||||
allowlist: [],
|
||||
},
|
||||
securityResponseHeaders: {},
|
||||
customResponseHeaders: {},
|
||||
requestId: {
|
||||
allowFromAnyIp: true,
|
||||
ipAllowlist: [],
|
||||
},
|
||||
shutdownTimeout: moment.duration(30, 'seconds'),
|
||||
keepaliveTimeout: 120_000,
|
||||
socketTimeout: 120_000,
|
||||
restrictInternalApis: false,
|
||||
versioned: {
|
||||
versionResolution: 'oldest',
|
||||
strictClientVersionCheck: true,
|
||||
},
|
||||
},
|
||||
server
|
||||
)
|
||||
);
|
||||
}
|
||||
if (path === 'externalUrl') {
|
||||
return new BehaviorSubject({
|
||||
|
@ -105,9 +111,9 @@ export const createCoreContext = (overrides: Partial<CoreContext> = {}): CoreCon
|
|||
});
|
||||
|
||||
/**
|
||||
* Creates a concrete HttpServer with a mocked context.
|
||||
* Creates a concrete HttpService with a mocked context.
|
||||
*/
|
||||
export const createHttpServer = ({
|
||||
export const createHttpService = ({
|
||||
buildNum,
|
||||
...overrides
|
||||
}: Partial<CoreContext & { buildNum: number }> = {}): HttpService => {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import { ContextService } from '@kbn/core-http-context-server-internal';
|
||||
import { createHttpServer, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks';
|
||||
import { typeRegistryMock } from '@kbn/core-saved-objects-base-server-mocks';
|
||||
|
@ -43,7 +43,7 @@ export const setupServer = async (coreId: symbol = defaultCoreId) => {
|
|||
const coreContext = createCoreContext({ coreId });
|
||||
const contextService = new ContextService(coreContext);
|
||||
|
||||
const server = createHttpServer(coreContext);
|
||||
const server = createHttpService(coreContext);
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
const httpSetup = await server.setup({
|
||||
context: contextService.setup({ pluginDependencies: new Map() }),
|
||||
|
|
|
@ -9,6 +9,17 @@ Object {
|
|||
"type": "string",
|
||||
},
|
||||
},
|
||||
"securitySchemes": Object {
|
||||
"apiKeyAuth": Object {
|
||||
"in": "header",
|
||||
"name": "Authorization",
|
||||
"type": "apiKey",
|
||||
},
|
||||
"basicAuth": Object {
|
||||
"scheme": "basic",
|
||||
"type": "http",
|
||||
},
|
||||
},
|
||||
},
|
||||
"externalDocs": undefined,
|
||||
"info": Object {
|
||||
|
@ -87,9 +98,6 @@ Object {
|
|||
Object {
|
||||
"basicAuth": Array [],
|
||||
},
|
||||
Object {
|
||||
"apiKeyAuth": Array [],
|
||||
},
|
||||
],
|
||||
"servers": Array [
|
||||
Object {
|
||||
|
@ -104,6 +112,17 @@ exports[`generateOpenApiDocument @kbn/config-schema generates the expected OpenA
|
|||
Object {
|
||||
"components": Object {
|
||||
"schemas": Object {},
|
||||
"securitySchemes": Object {
|
||||
"apiKeyAuth": Object {
|
||||
"in": "header",
|
||||
"name": "Authorization",
|
||||
"type": "apiKey",
|
||||
},
|
||||
"basicAuth": Object {
|
||||
"scheme": "basic",
|
||||
"type": "http",
|
||||
},
|
||||
},
|
||||
},
|
||||
"externalDocs": undefined,
|
||||
"info": Object {
|
||||
|
@ -334,9 +353,6 @@ Object {
|
|||
Object {
|
||||
"basicAuth": Array [],
|
||||
},
|
||||
Object {
|
||||
"apiKeyAuth": Array [],
|
||||
},
|
||||
],
|
||||
"servers": Array [
|
||||
Object {
|
||||
|
|
|
@ -68,15 +68,21 @@ export const generateOpenApiDocument = (
|
|||
},
|
||||
],
|
||||
paths,
|
||||
components: converter.getSchemaComponents(),
|
||||
security: [
|
||||
{
|
||||
basicAuth: [],
|
||||
components: {
|
||||
...converter.getSchemaComponents(),
|
||||
securitySchemes: {
|
||||
basicAuth: {
|
||||
type: 'http',
|
||||
scheme: 'basic',
|
||||
},
|
||||
apiKeyAuth: {
|
||||
type: 'apiKey',
|
||||
in: 'header',
|
||||
name: 'Authorization',
|
||||
},
|
||||
},
|
||||
{
|
||||
apiKeyAuth: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
security: [{ basicAuth: [] }],
|
||||
tags: opts.tags?.map((tag) => ({ name: tag })),
|
||||
externalDocs: opts.docsUrl ? { url: opts.docsUrl } : undefined,
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
InternalHttpServicePreboot,
|
||||
InternalHttpServiceSetup,
|
||||
} from '@kbn/core-http-server-internal';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import type { CapabilitiesSetup } from '@kbn/core-capabilities-server';
|
||||
import { CapabilitiesService } from '@kbn/core-capabilities-server-internal';
|
||||
|
||||
|
@ -35,7 +35,7 @@ describe('CapabilitiesService', () => {
|
|||
let serviceSetup: CapabilitiesSetup;
|
||||
|
||||
beforeEach(async () => {
|
||||
server = createHttpServer();
|
||||
server = createHttpService();
|
||||
httpPreboot = await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
httpSetup = await server.setup({
|
||||
context: contextServiceMock.createSetupContract(),
|
||||
|
|
|
@ -14,7 +14,7 @@ import { executionContextServiceMock } from '@kbn/core-execution-context-server-
|
|||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import type { IRouter } from '@kbn/core-http-server';
|
||||
import { HttpService } from '@kbn/core-http-server-internal';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import { registerRouteForBundle, FileHashCache } from '@kbn/core-apps-server-internal';
|
||||
|
||||
const buildHash = 'buildHash';
|
||||
|
@ -31,7 +31,7 @@ describe('bundle routes', () => {
|
|||
logger = loggingSystemMock.create();
|
||||
fileHashCache = new FileHashCache();
|
||||
|
||||
server = createHttpServer({ logger });
|
||||
server = createHttpService({ logger });
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
});
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import { executionContextServiceMock } from '@kbn/core-execution-context-server-
|
|||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import { ensureRawRequest } from '@kbn/core-http-router-server-internal';
|
||||
import { HttpService } from '@kbn/core-http-server-internal';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
|
||||
let server: HttpService;
|
||||
|
||||
|
@ -29,7 +29,7 @@ const setupDeps = {
|
|||
|
||||
beforeEach(async () => {
|
||||
logger = loggingSystemMock.create();
|
||||
server = createHttpServer({ logger });
|
||||
server = createHttpService({ logger });
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import supertest from 'supertest';
|
|||
import { kibanaPackageJson } from '@kbn/repo-info';
|
||||
import type { IRouter, RouteRegistrar } from '@kbn/core-http-server';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import { createConfigService, createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createConfigService, createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import { HttpService, HttpServerSetup } from '@kbn/core-http-server-internal';
|
||||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
@ -61,7 +61,7 @@ describe('core lifecycle handlers', () => {
|
|||
beforeEach(async () => {
|
||||
const configService = createConfigService(testConfig);
|
||||
logger = loggerMock.create();
|
||||
server = createHttpServer({ configService, logger });
|
||||
server = createHttpService({ configService, logger });
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
const serverSetup = await server.setup(setupDeps);
|
||||
router = serverSetup.createRouter('/');
|
||||
|
@ -243,7 +243,7 @@ describe('core lifecycle handlers', () => {
|
|||
restrictInternalApis: true,
|
||||
},
|
||||
});
|
||||
server = createHttpServer({ configService });
|
||||
server = createHttpService({ configService });
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
const serverSetup = await server.setup(setupDeps);
|
||||
router = serverSetup.createRouter('/');
|
||||
|
@ -317,7 +317,7 @@ describe('core lifecycle handlers with restrict internal routes enforced', () =>
|
|||
|
||||
beforeEach(async () => {
|
||||
const configService = createConfigService({ server: { restrictInternalApis: true } });
|
||||
server = createHttpServer({ configService });
|
||||
server = createHttpService({ configService });
|
||||
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
const serverSetup = await server.setup(setupDeps);
|
||||
|
@ -382,7 +382,7 @@ describe('core lifecycle handlers with no strict client version check', () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
server = createHttpServer({ configService, logger, buildNum: 1234 });
|
||||
server = createHttpService({ configService, logger, buildNum: 1234 });
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
const serverSetup = await server.setup(setupDeps);
|
||||
router = serverSetup.createRouter('/');
|
||||
|
|
164
src/core/server/integration_tests/http/oas.test.ts
Normal file
164
src/core/server/integration_tests/http/oas.test.ts
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import supertest from 'supertest';
|
||||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import { createConfigService, createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import type {
|
||||
InternalContextPreboot,
|
||||
InternalContextSetup,
|
||||
} from '@kbn/core-http-context-server-internal';
|
||||
import { InternalExecutionContextSetup } from '@kbn/core-execution-context-server-internal';
|
||||
import { IRouter } from '@kbn/core-http-server';
|
||||
|
||||
let prebootDeps: {
|
||||
context: jest.Mocked<InternalContextPreboot>;
|
||||
};
|
||||
let setupDeps: {
|
||||
context: jest.Mocked<InternalContextSetup>;
|
||||
executionContext: jest.Mocked<InternalExecutionContextSetup>;
|
||||
};
|
||||
beforeEach(async () => {
|
||||
prebootDeps = {
|
||||
context: contextServiceMock.createPrebootContract(),
|
||||
};
|
||||
const contextSetup = contextServiceMock.createSetupContract();
|
||||
setupDeps = {
|
||||
context: contextSetup,
|
||||
executionContext: executionContextServiceMock.createInternalSetupContract(),
|
||||
};
|
||||
});
|
||||
|
||||
let httpService: ReturnType<typeof createHttpService>;
|
||||
type ConfigServiceArgs = Parameters<typeof createConfigService>[0];
|
||||
async function startService(
|
||||
args: {
|
||||
config?: ConfigServiceArgs;
|
||||
createRoutes?: (getRouter: (pluginId?: symbol) => IRouter) => void;
|
||||
} = {}
|
||||
) {
|
||||
httpService = createHttpService({
|
||||
configService: createConfigService(args.config),
|
||||
});
|
||||
await httpService.preboot(prebootDeps);
|
||||
const { server: innerServer, createRouter } = await httpService.setup(setupDeps);
|
||||
if (args.createRoutes) {
|
||||
args.createRoutes((pluginId) => createRouter('/', pluginId));
|
||||
}
|
||||
await httpService.start();
|
||||
return {
|
||||
listener: innerServer.listener,
|
||||
};
|
||||
}
|
||||
|
||||
async function stopService() {
|
||||
await httpService?.stop();
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await stopService();
|
||||
});
|
||||
|
||||
it('is disabled by default', async () => {
|
||||
const server = await startService();
|
||||
supertest(server.listener).get('/api/oas').expect(404);
|
||||
});
|
||||
|
||||
it('handles requests when enabled', async () => {
|
||||
const server = await startService({ config: { server: { oas: { enabled: true } } } });
|
||||
const result = await supertest(server.listener).get('/api/oas');
|
||||
expect(result.status).toBe(200);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
queryParam: { pathStartsWith: '/api/include-test' },
|
||||
includes: {
|
||||
paths: {
|
||||
'/api/include-test': {
|
||||
get: {},
|
||||
post: {},
|
||||
},
|
||||
'/api/include-test/{id}': {},
|
||||
},
|
||||
},
|
||||
excludes: {
|
||||
paths: {
|
||||
'/my-other-plugin': {},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
queryParam: { pluginId: 'myPlugin' },
|
||||
includes: {
|
||||
paths: {
|
||||
'/api/include-test': {
|
||||
get: {},
|
||||
post: {},
|
||||
},
|
||||
'/api/include-test/{id}': {},
|
||||
},
|
||||
},
|
||||
excludes: {
|
||||
paths: {
|
||||
'/my-other-plugin': {},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
queryParam: { pluginId: 'nonExistant' },
|
||||
includes: {},
|
||||
excludes: {
|
||||
paths: {
|
||||
'/my-include-test': {},
|
||||
'/my-other-plugin': {},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
queryParam: { pluginId: 'myOtherPlugin', pathStartsWith: '/api/my-other-plugin' },
|
||||
includes: {
|
||||
paths: {
|
||||
'/api/my-other-plugin': {
|
||||
get: {},
|
||||
post: {},
|
||||
put: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
excludes: {
|
||||
paths: {
|
||||
'/my-include-test': {},
|
||||
},
|
||||
},
|
||||
},
|
||||
])(
|
||||
'can filter paths based on query params $queryParam',
|
||||
async ({ queryParam, includes, excludes }) => {
|
||||
const server = await startService({
|
||||
config: { server: { oas: { enabled: true } } },
|
||||
createRoutes: (getRouter) => {
|
||||
const router1 = getRouter(Symbol('myPlugin'));
|
||||
router1.get({ path: '/api/include-test', validate: false }, (_, __, res) => res.ok());
|
||||
router1.post({ path: '/api/include-test', validate: false }, (_, __, res) => res.ok());
|
||||
router1.get({ path: '/api/include-test/{id}', validate: false }, (_, __, res) => res.ok());
|
||||
router1.get({ path: '/api/exclude-test', validate: false }, (_, __, res) => res.ok());
|
||||
|
||||
const router2 = getRouter(Symbol('myOtherPlugin'));
|
||||
router2.get({ path: '/api/my-other-plugin', validate: false }, (_, __, res) => res.ok());
|
||||
router2.post({ path: '/api/my-other-plugin', validate: false }, (_, __, res) => res.ok());
|
||||
router2.put({ path: '/api/my-other-plugin', validate: false }, (_, __, res) => res.ok());
|
||||
},
|
||||
});
|
||||
const result = await supertest(server.listener).get('/api/oas').query(queryParam);
|
||||
expect(result.status).toBe(200);
|
||||
expect(result.body).toMatchObject(includes);
|
||||
expect(result.body).not.toMatchObject(excludes);
|
||||
}
|
||||
);
|
|
@ -11,7 +11,7 @@ import supertest from 'supertest';
|
|||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import { HttpService } from '@kbn/core-http-server-internal';
|
||||
|
||||
let server: HttpService;
|
||||
|
@ -24,7 +24,7 @@ const setupDeps = {
|
|||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
server = createHttpServer({ logger: loggingSystemMock.create() });
|
||||
server = createHttpService({ logger: loggingSystemMock.create() });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
|
|
@ -15,7 +15,7 @@ import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
|||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import type { HttpService } from '@kbn/core-http-server-internal';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
let server: HttpService;
|
||||
|
@ -31,7 +31,7 @@ const setupDeps = {
|
|||
beforeEach(async () => {
|
||||
logger = loggingSystemMock.create();
|
||||
|
||||
server = createHttpServer({ logger });
|
||||
server = createHttpService({ logger });
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
});
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import { executionContextServiceMock } from '@kbn/core-execution-context-server-
|
|||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import type { HttpService } from '@kbn/core-http-server-internal';
|
||||
import { ensureRawRequest } from '@kbn/core-http-router-server-internal';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import { inspect } from 'util';
|
||||
|
||||
let server: HttpService;
|
||||
|
@ -32,7 +32,7 @@ const setupDeps = {
|
|||
beforeEach(async () => {
|
||||
logger = loggingSystemMock.create();
|
||||
|
||||
server = createHttpServer({ logger });
|
||||
server = createHttpService({ logger });
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
});
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
|||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import { Router } from '@kbn/core-http-router-server-internal';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import type { HttpService } from '@kbn/core-http-server-internal';
|
||||
import { loggerMock } from '@kbn/logging-mocks';
|
||||
|
||||
|
@ -32,7 +32,7 @@ const setupDeps = {
|
|||
|
||||
beforeEach(async () => {
|
||||
logger = loggingSystemMock.create();
|
||||
server = createHttpServer({ logger });
|
||||
server = createHttpService({ logger });
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
});
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import { schema } from '@kbn/config-schema';
|
|||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import { createHttpServer, createConfigService } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService, createConfigService } from '@kbn/core-http-server-mocks';
|
||||
import type { HttpConfigType, HttpService } from '@kbn/core-http-server-internal';
|
||||
import type { IRouter } from '@kbn/core-http-server';
|
||||
import type { CliArgs } from '@kbn/config';
|
||||
|
@ -42,7 +42,7 @@ describe('Routing versioned requests', () => {
|
|||
options.useVersionResolutionStrategyForInternalPaths ?? [],
|
||||
},
|
||||
};
|
||||
server = createHttpServer({
|
||||
server = createHttpService({
|
||||
logger,
|
||||
env: createTestEnv({ envOptions: getEnvOptions({ cliArgs }) }),
|
||||
configService: createConfigService({
|
||||
|
|
|
@ -10,7 +10,7 @@ import { BehaviorSubject, Subject } from 'rxjs';
|
|||
import { take, filter } from 'rxjs';
|
||||
import supertest from 'supertest';
|
||||
import { Server as HapiServer } from '@hapi/hapi';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import type { IRouter } from '@kbn/core-http-server';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
import type { HttpService } from '@kbn/core-http-server-internal';
|
||||
|
@ -28,7 +28,7 @@ describe('ServerMetricsCollector', () => {
|
|||
const sendGet = (path: string) => supertest(hapiServer.listener).get(path);
|
||||
|
||||
beforeEach(async () => {
|
||||
server = createHttpServer();
|
||||
server = createHttpService();
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
const contextSetup = contextServiceMock.createSetupContract();
|
||||
const httpSetup = await server.setup({
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import supertest from 'supertest';
|
||||
import { ContextService } from '@kbn/core-http-context-server-internal';
|
||||
import type { HttpService, InternalHttpServiceSetup } from '@kbn/core-http-server-internal';
|
||||
import { createHttpServer, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks';
|
||||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import type { ICoreUsageStatsClient } from '@kbn/core-usage-data-base-server-internal';
|
||||
|
@ -42,7 +42,7 @@ describe('GET /api/saved_objects/{type}/{id} with allowApiAccess true', () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
const coreContext = createCoreContext({ coreId });
|
||||
server = createHttpServer(coreContext);
|
||||
server = createHttpService(coreContext);
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
|
||||
const contextService = new ContextService(coreContext);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import supertest from 'supertest';
|
||||
import { ContextService } from '@kbn/core-http-context-server-internal';
|
||||
import type { HttpService, InternalHttpServiceSetup } from '@kbn/core-http-server-internal';
|
||||
import { createHttpServer, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks';
|
||||
import type { ICoreUsageStatsClient } from '@kbn/core-usage-data-base-server-internal';
|
||||
import {
|
||||
|
@ -43,7 +43,7 @@ describe('GET /api/saved_objects/resolve/{type}/{id} with allowApiAccess true',
|
|||
|
||||
beforeEach(async () => {
|
||||
const coreContext = createCoreContext({ coreId });
|
||||
server = createHttpServer(coreContext);
|
||||
server = createHttpService(coreContext);
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
|
||||
const contextService = new ContextService(coreContext);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import supertest from 'supertest';
|
||||
import { ContextService } from '@kbn/core-http-context-server-internal';
|
||||
import type { HttpService, InternalHttpServiceSetup } from '@kbn/core-http-server-internal';
|
||||
import { createHttpServer, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks';
|
||||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||
import type { ICoreUsageStatsClient } from '@kbn/core-usage-data-base-server-internal';
|
||||
|
@ -43,7 +43,7 @@ describe('GET /api/saved_objects/{type}/{id}', () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
const coreContext = createCoreContext({ coreId });
|
||||
server = createHttpServer(coreContext);
|
||||
server = createHttpService(coreContext);
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
|
||||
const contextService = new ContextService(coreContext);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import supertest from 'supertest';
|
||||
import { ContextService } from '@kbn/core-http-context-server-internal';
|
||||
import type { HttpService, InternalHttpServiceSetup } from '@kbn/core-http-server-internal';
|
||||
import { createHttpServer, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService, createCoreContext } from '@kbn/core-http-server-mocks';
|
||||
import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks';
|
||||
import type { ICoreUsageStatsClient } from '@kbn/core-usage-data-base-server-internal';
|
||||
import {
|
||||
|
@ -44,7 +44,7 @@ describe('GET /api/saved_objects/resolve/{type}/{id}', () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
const coreContext = createCoreContext({ coreId });
|
||||
server = createHttpServer(coreContext);
|
||||
server = createHttpService(coreContext);
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
|
||||
const contextService = new ContextService(coreContext);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import supertest from 'supertest';
|
||||
import { createCoreContext, createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createCoreContext, createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import type { HttpService, InternalHttpServicePreboot } from '@kbn/core-http-server-internal';
|
||||
import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||
|
||||
|
@ -22,7 +22,7 @@ describe('GET /api/status', () => {
|
|||
const setupServer = async () => {
|
||||
const coreContext = createCoreContext({ coreId });
|
||||
|
||||
server = createHttpServer(coreContext);
|
||||
server = createHttpService(coreContext);
|
||||
httpPreboot = await server.preboot({
|
||||
context: contextServiceMock.createPrebootContract(),
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ import supertest from 'supertest';
|
|||
import { omit } from 'lodash';
|
||||
|
||||
import { ContextService } from '@kbn/core-http-context-server-internal';
|
||||
import { createCoreContext, createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createCoreContext, createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import type { HttpService, InternalHttpServiceSetup } from '@kbn/core-http-server-internal';
|
||||
import { metricsServiceMock } from '@kbn/core-metrics-server-mocks';
|
||||
import type { MetricsServiceSetup } from '@kbn/core-metrics-server';
|
||||
|
@ -48,7 +48,7 @@ describe('GET /api/status', () => {
|
|||
const coreContext = createCoreContext({ coreId });
|
||||
const contextService = new ContextService(coreContext);
|
||||
|
||||
server = createHttpServer(coreContext);
|
||||
server = createHttpService(coreContext);
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
httpSetup = await server.setup({
|
||||
context: contextService.setup({ pluginDependencies: new Map() }),
|
||||
|
|
|
@ -163,6 +163,7 @@
|
|||
"@kbn/core-security-server-mocks",
|
||||
"@kbn/core-security-browser",
|
||||
"@kbn/core-security-browser-mocks",
|
||||
"@kbn/core-execution-context-server-internal",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -20,12 +20,12 @@ import {
|
|||
metricsServiceMock,
|
||||
executionContextServiceMock,
|
||||
} from '@kbn/core/server/mocks';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import { registerStatsRoute } from '../stats';
|
||||
import supertest from 'supertest';
|
||||
import { CollectorSet } from '../../collector';
|
||||
|
||||
type HttpService = ReturnType<typeof createHttpServer>;
|
||||
type HttpService = ReturnType<typeof createHttpService>;
|
||||
type HttpSetup = Awaited<ReturnType<HttpService['setup']>>;
|
||||
|
||||
describe('/api/stats', () => {
|
||||
|
@ -35,7 +35,7 @@ describe('/api/stats', () => {
|
|||
let metrics: MetricsServiceSetup;
|
||||
|
||||
beforeEach(async () => {
|
||||
server = createHttpServer();
|
||||
server = createHttpService();
|
||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||
httpSetup = await server.setup({
|
||||
context: contextServiceMock.createSetupContract(),
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
*/
|
||||
import { setTimeout as setTimeoutPromise } from 'timers/promises';
|
||||
import { contextServiceMock, executionContextServiceMock } from '@kbn/core/server/mocks';
|
||||
import { createHttpServer } from '@kbn/core-http-server-mocks';
|
||||
import { createHttpService } from '@kbn/core-http-server-mocks';
|
||||
import supertest from 'supertest';
|
||||
import { APMEventClient } from '.';
|
||||
|
||||
describe('APMEventClient', () => {
|
||||
let server: ReturnType<typeof createHttpServer>;
|
||||
let server: ReturnType<typeof createHttpService>;
|
||||
|
||||
beforeEach(() => {
|
||||
server = createHttpServer();
|
||||
server = createHttpService();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue