Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [Logs UI] Reimplement log source configuration routes in plain HTTP+JSON (#64021) #64626

Merged
merged 2 commits into from
Apr 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as rt from 'io-ts';
import { badRequestErrorRT, forbiddenErrorRT, routeTimingMetadataRT } from '../shared';
import { logSourceConfigurationRT } from './log_source_configuration';

/**
* request
*/

export const getLogSourceConfigurationRequestParamsRT = rt.type({
// the id of the source configuration
sourceId: rt.string,
});

export type GetLogSourceConfigurationRequestParams = rt.TypeOf<
typeof getLogSourceConfigurationRequestParamsRT
>;

/**
* response
*/

export const getLogSourceConfigurationSuccessResponsePayloadRT = rt.intersection([
rt.type({
data: logSourceConfigurationRT,
}),
rt.partial({
timing: routeTimingMetadataRT,
}),
]);

export type GetLogSourceConfigurationSuccessResponsePayload = rt.TypeOf<
typeof getLogSourceConfigurationSuccessResponsePayloadRT
>;

export const getLogSourceConfigurationErrorResponsePayloadRT = rt.union([
badRequestErrorRT,
forbiddenErrorRT,
]);

export type GetLogSourceConfigurationErrorReponsePayload = rt.TypeOf<
typeof getLogSourceConfigurationErrorResponsePayloadRT
>;

export const getLogSourceConfigurationResponsePayloadRT = rt.union([
getLogSourceConfigurationSuccessResponsePayloadRT,
getLogSourceConfigurationErrorResponsePayloadRT,
]);

export type GetLogSourceConfigurationReponsePayload = rt.TypeOf<
typeof getLogSourceConfigurationResponsePayloadRT
>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as rt from 'io-ts';
import { routeTimingMetadataRT } from '../shared';
import {
getLogSourceConfigurationPath,
LOG_SOURCE_CONFIGURATION_PATH,
} from './log_source_configuration';

export const LOG_SOURCE_STATUS_PATH_SUFFIX = 'status';
export const LOG_SOURCE_STATUS_PATH = `${LOG_SOURCE_CONFIGURATION_PATH}/${LOG_SOURCE_STATUS_PATH_SUFFIX}`;
export const getLogSourceStatusPath = (sourceId: string) =>
`${getLogSourceConfigurationPath(sourceId)}/${LOG_SOURCE_STATUS_PATH_SUFFIX}`;

/**
* request
*/

export const getLogSourceStatusRequestParamsRT = rt.type({
// the id of the source configuration
sourceId: rt.string,
});

export type GetLogSourceStatusRequestParams = rt.TypeOf<typeof getLogSourceStatusRequestParamsRT>;

/**
* response
*/

const logIndexFieldRT = rt.strict({
name: rt.string,
type: rt.string,
searchable: rt.boolean,
aggregatable: rt.boolean,
});

export type LogIndexField = rt.TypeOf<typeof logIndexFieldRT>;

const logSourceStatusRT = rt.strict({
logIndexFields: rt.array(logIndexFieldRT),
logIndexNames: rt.array(rt.string),
});

export type LogSourceStatus = rt.TypeOf<typeof logSourceStatusRT>;

export const getLogSourceStatusSuccessResponsePayloadRT = rt.intersection([
rt.type({
data: logSourceStatusRT,
}),
rt.partial({
timing: routeTimingMetadataRT,
}),
]);

export type GetLogSourceStatusSuccessResponsePayload = rt.TypeOf<
typeof getLogSourceStatusSuccessResponsePayloadRT
>;
10 changes: 10 additions & 0 deletions x-pack/plugins/infra/common/http_api/log_sources/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export * from './get_log_source_configuration';
export * from './get_log_source_status';
export * from './log_source_configuration';
export * from './patch_log_source_configuration';
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as rt from 'io-ts';

export const LOG_SOURCE_CONFIGURATION_PATH_PREFIX = '/api/infra/log_source_configurations';
export const LOG_SOURCE_CONFIGURATION_PATH = `${LOG_SOURCE_CONFIGURATION_PATH_PREFIX}/{sourceId}`;
export const getLogSourceConfigurationPath = (sourceId: string) =>
`${LOG_SOURCE_CONFIGURATION_PATH_PREFIX}/${sourceId}`;

export const logSourceConfigurationOriginRT = rt.keyof({
fallback: null,
internal: null,
stored: null,
});

export type LogSourceConfigurationOrigin = rt.TypeOf<typeof logSourceConfigurationOriginRT>;

const logSourceFieldsConfigurationRT = rt.strict({
timestamp: rt.string,
tiebreaker: rt.string,
});

const logSourceCommonColumnConfigurationRT = rt.strict({
id: rt.string,
});

const logSourceTimestampColumnConfigurationRT = rt.strict({
timestampColumn: logSourceCommonColumnConfigurationRT,
});

const logSourceMessageColumnConfigurationRT = rt.strict({
messageColumn: logSourceCommonColumnConfigurationRT,
});

const logSourceFieldColumnConfigurationRT = rt.strict({
fieldColumn: rt.intersection([
logSourceCommonColumnConfigurationRT,
rt.strict({
field: rt.string,
}),
]),
});

const logSourceColumnConfigurationRT = rt.union([
logSourceTimestampColumnConfigurationRT,
logSourceMessageColumnConfigurationRT,
logSourceFieldColumnConfigurationRT,
]);

export const logSourceConfigurationPropertiesRT = rt.strict({
name: rt.string,
description: rt.string,
logAlias: rt.string,
fields: logSourceFieldsConfigurationRT,
logColumns: rt.array(logSourceColumnConfigurationRT),
});

export type LogSourceConfigurationProperties = rt.TypeOf<typeof logSourceConfigurationPropertiesRT>;

export const logSourceConfigurationRT = rt.exact(
rt.intersection([
rt.type({
id: rt.string,
origin: logSourceConfigurationOriginRT,
configuration: logSourceConfigurationPropertiesRT,
}),
rt.partial({
updatedAt: rt.number,
version: rt.string,
}),
])
);

export type LogSourceConfiguration = rt.TypeOf<typeof logSourceConfigurationRT>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as rt from 'io-ts';
import { badRequestErrorRT, forbiddenErrorRT } from '../shared';
import { getLogSourceConfigurationSuccessResponsePayloadRT } from './get_log_source_configuration';
import { logSourceConfigurationPropertiesRT } from './log_source_configuration';

/**
* request
*/

export const patchLogSourceConfigurationRequestParamsRT = rt.type({
// the id of the source configuration
sourceId: rt.string,
});

export type PatchLogSourceConfigurationRequestParams = rt.TypeOf<
typeof patchLogSourceConfigurationRequestParamsRT
>;

const logSourceConfigurationProperiesPatchRT = rt.partial({
...logSourceConfigurationPropertiesRT.type.props,
fields: rt.partial(logSourceConfigurationPropertiesRT.type.props.fields.type.props),
});

export type LogSourceConfigurationPropertiesPatch = rt.TypeOf<
typeof logSourceConfigurationProperiesPatchRT
>;

export const patchLogSourceConfigurationRequestBodyRT = rt.type({
data: logSourceConfigurationProperiesPatchRT,
});

export type PatchLogSourceConfigurationRequestBody = rt.TypeOf<
typeof patchLogSourceConfigurationRequestBodyRT
>;

/**
* response
*/

export const patchLogSourceConfigurationSuccessResponsePayloadRT = getLogSourceConfigurationSuccessResponsePayloadRT;

export type PatchLogSourceConfigurationSuccessResponsePayload = rt.TypeOf<
typeof patchLogSourceConfigurationSuccessResponsePayloadRT
>;

export const patchLogSourceConfigurationResponsePayloadRT = rt.union([
patchLogSourceConfigurationSuccessResponsePayloadRT,
badRequestErrorRT,
forbiddenErrorRT,
]);

export type PatchLogSourceConfigurationReponsePayload = rt.TypeOf<
typeof patchLogSourceConfigurationResponsePayloadRT
>;
20 changes: 17 additions & 3 deletions x-pack/plugins/infra/common/runtime_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { identity } from 'fp-ts/lib/function';
import { pipe } from 'fp-ts/lib/pipeable';
import { Errors, Type } from 'io-ts';
import { failure } from 'io-ts/lib/PathReporter';
import { RouteValidationFunction } from 'kibana/server';

type ErrorFactory = (message: string) => Error;

Expand All @@ -18,8 +19,21 @@ export const throwErrors = (createError: ErrorFactory) => (errors: Errors) => {
throw createError(failure(errors).join('\n'));
};

export const decodeOrThrow = <A, O, I>(
runtimeType: Type<A, O, I>,
export const decodeOrThrow = <DecodedValue, EncodedValue, InputValue>(
runtimeType: Type<DecodedValue, EncodedValue, InputValue>,
createError: ErrorFactory = createPlainError
) => (inputValue: I) =>
) => (inputValue: InputValue) =>
pipe(runtimeType.decode(inputValue), fold(throwErrors(createError), identity));

type ValdidationResult<Value> = ReturnType<RouteValidationFunction<Value>>;

export const createValidationFunction = <DecodedValue, EncodedValue, InputValue>(
runtimeType: Type<DecodedValue, EncodedValue, InputValue>
): RouteValidationFunction<DecodedValue> => (inputValue, { badRequest, ok }) =>
pipe(
runtimeType.decode(inputValue),
fold<Errors, DecodedValue, ValdidationResult<DecodedValue>>(
(errors: Errors) => badRequest(failure(errors).join('\n')),
(result: DecodedValue) => ok(result)
)
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/

export * from './input_fields';
export { SourceConfigurationSettings } from './source_configuration_settings';
export { ViewSourceConfigurationButton } from './view_source_configuration_button';
6 changes: 3 additions & 3 deletions x-pack/plugins/infra/public/containers/logs/log_flyout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import createContainer from 'constate';
import { isString } from 'lodash';
import React, { useContext, useEffect, useMemo, useState } from 'react';

import { LogEntriesItem } from '../../../common/http_api';
import { UrlStateContainer } from '../../utils/url_state';
import { useTrackedPromise } from '../../utils/use_tracked_promise';
import { Source } from '../source';
import { fetchLogEntriesItem } from './log_entries/api/fetch_log_entries_item';
import { LogEntriesItem } from '../../../common/http_api';
import { useLogSourceContext } from './log_source';

export enum FlyoutVisibility {
hidden = 'hidden',
Expand All @@ -26,7 +26,7 @@ export interface FlyoutOptionsUrlState {
}

export const useLogFlyout = () => {
const { sourceId } = useContext(Source.Context);
const { sourceId } = useLogSourceContext();
const [flyoutVisible, setFlyoutVisibility] = useState<boolean>(false);
const [flyoutId, setFlyoutId] = useState<string | null>(null);
const [flyoutItem, setFlyoutItem] = useState<LogEntriesItem | null>(null);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import {
getLogSourceConfigurationPath,
getLogSourceConfigurationSuccessResponsePayloadRT,
} from '../../../../../common/http_api/log_sources';
import { decodeOrThrow } from '../../../../../common/runtime_types';
import { npStart } from '../../../../legacy_singletons';

export const callFetchLogSourceConfigurationAPI = async (sourceId: string) => {
const response = await npStart.http.fetch(getLogSourceConfigurationPath(sourceId), {
method: 'GET',
});

return decodeOrThrow(getLogSourceConfigurationSuccessResponsePayloadRT)(response);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import {
getLogSourceStatusPath,
getLogSourceStatusSuccessResponsePayloadRT,
} from '../../../../../common/http_api/log_sources';
import { decodeOrThrow } from '../../../../../common/runtime_types';
import { npStart } from '../../../../legacy_singletons';

export const callFetchLogSourceStatusAPI = async (sourceId: string) => {
const response = await npStart.http.fetch(getLogSourceStatusPath(sourceId), {
method: 'GET',
});

return decodeOrThrow(getLogSourceStatusSuccessResponsePayloadRT)(response);
};
Loading