Skip to content

Commit

Permalink
Adding KibanaRequest#uuid (#76822)
Browse files Browse the repository at this point in the history
* Adding KibanaRequest#uuid

* Adding tests

* Fixing test which was mocking uuid.v4() to get expected IDs

* Fixing another mock

* Updating docs

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
kobelb and elasticmachine committed Sep 21, 2020
1 parent 8d0f260 commit 0b5e64e
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ export declare class KibanaRequest<Params = unknown, Query = unknown, Body = unk
| [route](./kibana-plugin-core-server.kibanarequest.route.md) | | <code>RecursiveReadonly&lt;KibanaRequestRoute&lt;Method&gt;&gt;</code> | matched route details |
| [socket](./kibana-plugin-core-server.kibanarequest.socket.md) | | <code>IKibanaSocket</code> | [IKibanaSocket](./kibana-plugin-core-server.ikibanasocket.md) |
| [url](./kibana-plugin-core-server.kibanarequest.url.md) | | <code>Url</code> | a WHATWG URL standard object. |
| [uuid](./kibana-plugin-core-server.kibanarequest.uuid.md) | | <code>string</code> | A UUID to identify this request. |

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [KibanaRequest](./kibana-plugin-core-server.kibanarequest.md) &gt; [uuid](./kibana-plugin-core-server.kibanarequest.uuid.md)

## KibanaRequest.uuid property

A UUID to identify this request.

<b>Signature:</b>

```typescript
readonly uuid: string;
```

## Remarks

This value is NOT sourced from the incoming request's `X-Opaque-Id` header. it is always a UUID uniquely identifying the request.

4 changes: 2 additions & 2 deletions src/core/server/elasticsearch/client/cluster_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ describe('ClusterClient', () => {

const clusterClient = new ClusterClient(config, logger, getAuthHeaders);
const request = httpServerMock.createKibanaRequest({
kibanaRequestState: { requestId: 'my-fake-id' },
kibanaRequestState: { requestId: 'my-fake-id', requestUuid: 'ignore-this-id' },
});

clusterClient.asScoped(request);
Expand Down Expand Up @@ -284,7 +284,7 @@ describe('ClusterClient', () => {
const clusterClient = new ClusterClient(config, logger, getAuthHeaders);
const request = httpServerMock.createKibanaRequest({
headers: { foo: 'request' },
kibanaRequestState: { requestId: 'from request' },
kibanaRequestState: { requestId: 'from request', requestUuid: 'ignore-this-id' },
});

clusterClient.asScoped(request);
Expand Down
4 changes: 3 additions & 1 deletion src/core/server/elasticsearch/legacy/cluster_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,9 @@ describe('#asScoped', () => {

test('passes x-opaque-id header with request id', () => {
clusterClient.asScoped(
httpServerMock.createKibanaRequest({ kibanaRequestState: { requestId: 'alpha' } })
httpServerMock.createKibanaRequest({
kibanaRequestState: { requestId: 'alpha', requestUuid: 'ignore-this-id' },
})
);

expect(MockScopedClusterClient).toHaveBeenCalledTimes(1);
Expand Down
2 changes: 1 addition & 1 deletion src/core/server/http/http_server.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function createKibanaRequestMock<P = any, Q = any, B = any>({
routeAuthRequired,
validation = {},
kibanaRouteOptions = { xsrfRequired: true },
kibanaRequestState = { requestId: '123' },
kibanaRequestState = { requestId: '123', requestUuid: '123e4567-e89b-12d3-a456-426614174000' },
auth = { isAuthenticated: true },
}: RequestFixtureOptions<P, Q, B> = {}) {
const queryString = stringify(query, { sort: false });
Expand Down
2 changes: 2 additions & 0 deletions src/core/server/http/http_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import { Server } from 'hapi';
import HapiStaticFiles from 'inert';
import url from 'url';
import uuid from 'uuid';

import { Logger, LoggerFactory } from '../logging';
import { HttpConfig } from './http_config';
Expand Down Expand Up @@ -315,6 +316,7 @@ export class HttpServer {
request.app = {
...(request.app ?? {}),
requestId: getRequestId(request, config.requestId),
requestUuid: uuid.v4(),
} as KibanaRequestState;
return responseToolkit.continue;
});
Expand Down
21 changes: 21 additions & 0 deletions src/core/server/http/integration_tests/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/

jest.mock('uuid', () => ({
v4: jest.fn().mockReturnValue('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'),
}));

import supertest from 'supertest';

import { HttpService } from '../http_service';
Expand Down Expand Up @@ -308,4 +313,20 @@ describe('KibanaRequest', () => {
expect(resp3.body).toEqual({ requestId: 'gamma' });
});
});

describe('request uuid', () => {
it('generates a UUID', async () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, async (context, req, res) => {
return res.ok({ body: { requestUuid: req.uuid } });
});
await server.start();

const st = supertest(innerServer.listener);

const resp1 = await st.get('/').expect(200);
expect(resp1.body.requestUuid).toBe('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx');
});
});
});
28 changes: 28 additions & 0 deletions src/core/server/http/router/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,34 @@ describe('KibanaRequest', () => {
});
});

describe('uuid property', () => {
it('uses the request.app.requestUuid property if present', () => {
const request = httpServerMock.createRawRequest({
app: { requestUuid: '123e4567-e89b-12d3-a456-426614174000' },
});
const kibanaRequest = KibanaRequest.from(request);
expect(kibanaRequest.uuid).toEqual('123e4567-e89b-12d3-a456-426614174000');
});

it('generates a new UUID if request.app property is not present', () => {
// Undefined app property
const request = httpServerMock.createRawRequest({
app: undefined,
});
const kibanaRequest = KibanaRequest.from(request);
expect(kibanaRequest.uuid).toEqual('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx');
});

it('generates a new UUID if request.app.requestUuid property is not present', () => {
// Undefined app.requestUuid property
const request = httpServerMock.createRawRequest({
app: {},
});
const kibanaRequest = KibanaRequest.from(request);
expect(kibanaRequest.uuid).toEqual('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx');
});
});

describe('get all headers', () => {
it('returns all headers', () => {
const request = httpServerMock.createRawRequest({
Expand Down
14 changes: 12 additions & 2 deletions src/core/server/http/router/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface KibanaRouteOptions extends RouteOptionsApp {
*/
export interface KibanaRequestState extends ApplicationState {
requestId: string;
requestUuid: string;
}

/**
Expand Down Expand Up @@ -152,6 +153,14 @@ export class KibanaRequest<
* per request.
*/
public readonly id: string;
/**
* A UUID to identify this request.
*
* @remarks
* This value is NOT sourced from the incoming request's `X-Opaque-Id` header. it
* is always a UUID uniquely identifying the request.
*/
public readonly uuid: string;
/** a WHATWG URL standard object. */
public readonly url: Url;
/** matched route details */
Expand Down Expand Up @@ -189,10 +198,11 @@ export class KibanaRequest<
// until that time we have to expose all the headers
private readonly withoutSecretHeaders: boolean
) {
// The `requestId` property will not be populated for requests that are 'faked' by internal systems that leverage
// The `requestId` and `requestUuid` properties will not be populated for requests that are 'faked' by internal systems that leverage
// KibanaRequest in conjunction with scoped Elaticcsearch and SavedObjectsClient in order to pass credentials.
// In these cases, the id defaults to a newly generated UUID.
// In these cases, the ids default to a newly generated UUID.
this.id = (request.app as KibanaRequestState | undefined)?.requestId ?? uuid.v4();
this.uuid = (request.app as KibanaRequestState | undefined)?.requestUuid ?? uuid.v4();

this.url = request.url;
this.headers = deepFreeze({ ...request.headers });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,11 @@ describe(`POST ${URL}`, () => {

describe('createNewCopies enabled', () => {
it('imports objects, regenerating all IDs/reference IDs present, and resetting all origin IDs', async () => {
mockUuidv4.mockReturnValueOnce('new-id-1').mockReturnValueOnce('new-id-2');
mockUuidv4
.mockReturnValueOnce('foo') // a uuid.v4() is generated for the request.id
.mockReturnValueOnce('foo') // another uuid.v4() is used for the request.uuid
.mockReturnValueOnce('new-id-1')
.mockReturnValueOnce('new-id-2');
savedObjectsClient.bulkGet.mockResolvedValueOnce({ saved_objects: [mockIndexPattern] });
const obj1 = {
type: 'visualization',
Expand All @@ -490,7 +494,6 @@ describe(`POST ${URL}`, () => {
const result = await supertest(httpSetup.server.listener)
.post(`${URL}?createNewCopies=true`)
.set('content-Type', 'multipart/form-data; boundary=EXAMPLE')
.set('x-opaque-id', uuidv4()) // prevents src/core/server/http/http_tools.ts from using our mocked uuidv4 to generate a unique ID for this request
.send(
[
'--EXAMPLE',
Expand Down
1 change: 1 addition & 0 deletions src/core/server/server.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown, Me
// (undocumented)
readonly socket: IKibanaSocket;
readonly url: Url;
readonly uuid: string;
}

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ describe('AuditTrailClient', () => {
beforeEach(() => {
event$ = new Subject();
client = new AuditTrailClient(
httpServerMock.createKibanaRequest({ kibanaRequestState: { requestId: 'request id alpha' } }),
httpServerMock.createKibanaRequest({
kibanaRequestState: { requestId: 'request id alpha', requestUuid: 'ignore-me' },
}),
event$,
deps
);
Expand Down

0 comments on commit 0b5e64e

Please sign in to comment.