[Ingest] Add Global settings flyout (#64276)
This commit is contained in:
parent
8c05a724e7
commit
6c98b2368b
33 changed files with 899 additions and 54 deletions
|
@ -12,3 +12,4 @@ export * from './datasource';
|
||||||
export * from './epm';
|
export * from './epm';
|
||||||
export * from './output';
|
export * from './output';
|
||||||
export * from './enrollment_api_key';
|
export * from './enrollment_api_key';
|
||||||
|
export * from './settings';
|
||||||
|
|
|
@ -48,6 +48,19 @@ export const AGENT_CONFIG_API_ROUTES = {
|
||||||
FULL_INFO_PATTERN: `${AGENT_CONFIG_API_ROOT}/{agentConfigId}/full`,
|
FULL_INFO_PATTERN: `${AGENT_CONFIG_API_ROOT}/{agentConfigId}/full`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Output API routes
|
||||||
|
export const OUTPUT_API_ROUTES = {
|
||||||
|
LIST_PATTERN: `${API_ROOT}/outputs`,
|
||||||
|
INFO_PATTERN: `${API_ROOT}/outputs/{outputId}`,
|
||||||
|
UPDATE_PATTERN: `${API_ROOT}/outputs/{outputId}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Settings API routes
|
||||||
|
export const SETTINGS_API_ROUTES = {
|
||||||
|
INFO_PATTERN: `${API_ROOT}/settings`,
|
||||||
|
UPDATE_PATTERN: `${API_ROOT}/settings`,
|
||||||
|
};
|
||||||
|
|
||||||
// Agent API routes
|
// Agent API routes
|
||||||
export const AGENT_API_ROUTES = {
|
export const AGENT_API_ROUTES = {
|
||||||
LIST_PATTERN: `${FLEET_API_ROOT}/agents`,
|
LIST_PATTERN: `${FLEET_API_ROOT}/agents`,
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
* 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 const GLOBAL_SETTINGS_SAVED_OBJECT_TYPE = 'ingest_manager_settings';
|
|
@ -13,6 +13,8 @@ import {
|
||||||
AGENT_API_ROUTES,
|
AGENT_API_ROUTES,
|
||||||
ENROLLMENT_API_KEY_ROUTES,
|
ENROLLMENT_API_KEY_ROUTES,
|
||||||
SETUP_API_ROUTE,
|
SETUP_API_ROUTE,
|
||||||
|
OUTPUT_API_ROUTES,
|
||||||
|
SETTINGS_API_ROUTES,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
|
|
||||||
export const epmRouteService = {
|
export const epmRouteService = {
|
||||||
|
@ -112,6 +114,18 @@ export const agentRouteService = {
|
||||||
getStatusPath: () => AGENT_API_ROUTES.STATUS_PATTERN,
|
getStatusPath: () => AGENT_API_ROUTES.STATUS_PATTERN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const outputRoutesService = {
|
||||||
|
getInfoPath: (outputId: string) => OUTPUT_API_ROUTES.INFO_PATTERN.replace('{outputId}', outputId),
|
||||||
|
getUpdatePath: (outputId: string) =>
|
||||||
|
OUTPUT_API_ROUTES.UPDATE_PATTERN.replace('{outputId}', outputId),
|
||||||
|
getListPath: () => OUTPUT_API_ROUTES.LIST_PATTERN,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const settingsRoutesService = {
|
||||||
|
getInfoPath: () => SETTINGS_API_ROUTES.INFO_PATTERN,
|
||||||
|
getUpdatePath: () => SETTINGS_API_ROUTES.UPDATE_PATTERN,
|
||||||
|
};
|
||||||
|
|
||||||
export const enrollmentAPIKeyRouteService = {
|
export const enrollmentAPIKeyRouteService = {
|
||||||
getListPath: () => ENROLLMENT_API_KEY_ROUTES.LIST_PATTERN,
|
getListPath: () => ENROLLMENT_API_KEY_ROUTES.LIST_PATTERN,
|
||||||
getCreatePath: () => ENROLLMENT_API_KEY_ROUTES.CREATE_PATTERN,
|
getCreatePath: () => ENROLLMENT_API_KEY_ROUTES.CREATE_PATTERN,
|
||||||
|
|
|
@ -11,3 +11,4 @@ export * from './data_stream';
|
||||||
export * from './output';
|
export * from './output';
|
||||||
export * from './epm';
|
export * from './epm';
|
||||||
export * from './enrollment_api_key';
|
export * from './enrollment_api_key';
|
||||||
|
export * from './settings';
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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 { SavedObjectAttributes } from 'src/core/public';
|
||||||
|
|
||||||
|
interface BaseSettings {
|
||||||
|
agent_auto_upgrade?: boolean;
|
||||||
|
package_auto_upgrade?: boolean;
|
||||||
|
kibana_url?: string;
|
||||||
|
kibana_ca_sha256?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Settings extends BaseSettings {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SettingsSOAttributes extends BaseSettings, SavedObjectAttributes {}
|
|
@ -12,3 +12,5 @@ export * from './fleet_setup';
|
||||||
export * from './epm';
|
export * from './epm';
|
||||||
export * from './enrollment_api_key';
|
export * from './enrollment_api_key';
|
||||||
export * from './install_script';
|
export * from './install_script';
|
||||||
|
export * from './output';
|
||||||
|
export * from './settings';
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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 { Output } from '../models';
|
||||||
|
|
||||||
|
export interface GetOneOutputResponse {
|
||||||
|
item: Output;
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetOneOutputRequest {
|
||||||
|
params: {
|
||||||
|
outputId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PutOutputRequest {
|
||||||
|
params: {
|
||||||
|
outputId: string;
|
||||||
|
};
|
||||||
|
body: {
|
||||||
|
hosts?: string[];
|
||||||
|
ca_sha256?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PutOutputResponse {
|
||||||
|
item: Output;
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetOutputsResponse {
|
||||||
|
items: Output[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
perPage: number;
|
||||||
|
success: boolean;
|
||||||
|
}
|
|
@ -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 { Settings } from '../models';
|
||||||
|
|
||||||
|
export interface GetSettingsResponse {
|
||||||
|
item: Settings;
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PutSettingsRequest {
|
||||||
|
body: Partial<Omit<Settings, 'id'>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PutSettingsResponse {
|
||||||
|
item: Settings;
|
||||||
|
success: boolean;
|
||||||
|
}
|
|
@ -7,3 +7,4 @@ export { Loading } from './loading';
|
||||||
export { Error } from './error';
|
export { Error } from './error';
|
||||||
export { Header, HeaderProps } from './header';
|
export { Header, HeaderProps } from './header';
|
||||||
export { AlphaMessaging } from './alpha_messaging';
|
export { AlphaMessaging } from './alpha_messaging';
|
||||||
|
export * from './settings_flyout';
|
||||||
|
|
|
@ -0,0 +1,240 @@
|
||||||
|
/*
|
||||||
|
* 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 React, { useEffect } from 'react';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import {
|
||||||
|
EuiFlyout,
|
||||||
|
EuiFlyoutBody,
|
||||||
|
EuiFlyoutHeader,
|
||||||
|
EuiTitle,
|
||||||
|
EuiFlexGroup,
|
||||||
|
EuiFlexItem,
|
||||||
|
EuiButtonEmpty,
|
||||||
|
EuiSpacer,
|
||||||
|
EuiButton,
|
||||||
|
EuiFlyoutFooter,
|
||||||
|
EuiForm,
|
||||||
|
EuiFormRow,
|
||||||
|
EuiFieldText,
|
||||||
|
EuiRadioGroup,
|
||||||
|
EuiComboBox,
|
||||||
|
} from '@elastic/eui';
|
||||||
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
|
import { EuiText } from '@elastic/eui';
|
||||||
|
import { useInput, useComboInput, useCore, useGetSettings, sendPutSettings } from '../hooks';
|
||||||
|
import { useGetOutputs, sendPutOutput } from '../hooks/use_request/outputs';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useSettingsForm(outputId: string | undefined) {
|
||||||
|
const { notifications } = useCore();
|
||||||
|
const kibanaUrlInput = useInput();
|
||||||
|
const elasticsearchUrlInput = useComboInput([]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
onSubmit: async () => {
|
||||||
|
try {
|
||||||
|
if (!outputId) {
|
||||||
|
throw new Error('Unable to load outputs');
|
||||||
|
}
|
||||||
|
await sendPutOutput(outputId, {
|
||||||
|
hosts: elasticsearchUrlInput.value,
|
||||||
|
});
|
||||||
|
await sendPutSettings({
|
||||||
|
kibana_url: kibanaUrlInput.value,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
notifications.toasts.addError(error, {
|
||||||
|
title: 'Error',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
notifications.toasts.addSuccess(
|
||||||
|
i18n.translate('xpack.ingestManager.settings.success.message', {
|
||||||
|
defaultMessage: 'Settings saved',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
inputs: {
|
||||||
|
kibanaUrl: kibanaUrlInput,
|
||||||
|
elasticsearchUrl: elasticsearchUrlInput,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SettingFlyout: React.FunctionComponent<Props> = ({ onClose }) => {
|
||||||
|
const core = useCore();
|
||||||
|
const settingsRequest = useGetSettings();
|
||||||
|
const settings = settingsRequest?.data?.item;
|
||||||
|
const outputsRequest = useGetOutputs();
|
||||||
|
const output = outputsRequest.data?.items?.[0];
|
||||||
|
const { inputs, onSubmit } = useSettingsForm(output?.id);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (output) {
|
||||||
|
inputs.elasticsearchUrl.setValue(output.hosts || []);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [output]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (settings) {
|
||||||
|
inputs.kibanaUrl.setValue(
|
||||||
|
settings.kibana_url || `${window.location.origin}${core.http.basePath.get()}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [settings]);
|
||||||
|
|
||||||
|
const body = (
|
||||||
|
<EuiForm>
|
||||||
|
<EuiRadioGroup
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
id: 'enabled',
|
||||||
|
label: i18n.translate('xpack.ingestManager.settings.autoUpgradeEnabledLabel', {
|
||||||
|
defaultMessage:
|
||||||
|
'Automatically update agent binaries to use the latest minor version.',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'disabled',
|
||||||
|
disabled: true,
|
||||||
|
label: i18n.translate('xpack.ingestManager.settings.autoUpgradeDisabledLabel', {
|
||||||
|
defaultMessage: 'Manually manage agent binary versions. Requires Gold license.',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
idSelected={'enabled'}
|
||||||
|
onChange={id => {}}
|
||||||
|
legend={{
|
||||||
|
children: (
|
||||||
|
<EuiTitle size="xs">
|
||||||
|
<h3>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.settings.autoUpgradeFieldLabel"
|
||||||
|
defaultMessage="Elastic Agent binary version"
|
||||||
|
/>
|
||||||
|
</h3>
|
||||||
|
</EuiTitle>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<EuiSpacer size="l" />
|
||||||
|
<EuiRadioGroup
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
id: 'enabled',
|
||||||
|
label: i18n.translate(
|
||||||
|
'xpack.ingestManager.settings.integrationUpgradeEnabledFieldLabel',
|
||||||
|
{
|
||||||
|
defaultMessage:
|
||||||
|
'Automatically update Integrations to the latest version to receive the latest assets. Agent configurations may need to be updated in order to use new features.',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'disabled',
|
||||||
|
disabled: true,
|
||||||
|
label: i18n.translate(
|
||||||
|
'xpack.ingestManager.settings.integrationUpgradeDisabledFieldLabel',
|
||||||
|
{
|
||||||
|
defaultMessage: 'Manually manage integration versions yourself.',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
idSelected={'enabled'}
|
||||||
|
onChange={id => {}}
|
||||||
|
legend={{
|
||||||
|
children: (
|
||||||
|
<EuiTitle size="xs">
|
||||||
|
<h3>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.settings.integrationUpgradeFieldLabel"
|
||||||
|
defaultMessage="Elastic integration version"
|
||||||
|
/>
|
||||||
|
</h3>
|
||||||
|
</EuiTitle>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<EuiSpacer size="l" />
|
||||||
|
<EuiTitle size="s">
|
||||||
|
<h3>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.settings.globalOutputTitle"
|
||||||
|
defaultMessage="Global output"
|
||||||
|
/>
|
||||||
|
</h3>
|
||||||
|
</EuiTitle>
|
||||||
|
<EuiSpacer size="s" />
|
||||||
|
<EuiText color="subdued" size="s">
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.settings.globalOutputDescription"
|
||||||
|
defaultMessage="The global output is applied to all agent configurations and specifies where data is sent."
|
||||||
|
/>
|
||||||
|
</EuiText>
|
||||||
|
<EuiSpacer size="m" />
|
||||||
|
<EuiFormRow>
|
||||||
|
<EuiFormRow
|
||||||
|
label={i18n.translate('xpack.ingestManager.settings.kibanaUrlLabel', {
|
||||||
|
defaultMessage: 'Kibana URL',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<EuiFieldText required={true} {...inputs.kibanaUrl.props} name="kibanaUrl" />
|
||||||
|
</EuiFormRow>
|
||||||
|
</EuiFormRow>
|
||||||
|
<EuiSpacer size="m" />
|
||||||
|
<EuiFormRow>
|
||||||
|
<EuiFormRow
|
||||||
|
label={i18n.translate('xpack.ingestManager.settings.elasticsearchUrlLabel', {
|
||||||
|
defaultMessage: 'Elasticsearch URL',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<EuiComboBox noSuggestions {...inputs.elasticsearchUrl.props} />
|
||||||
|
</EuiFormRow>
|
||||||
|
</EuiFormRow>
|
||||||
|
</EuiForm>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EuiFlyout onClose={onClose} size="l" maxWidth={640}>
|
||||||
|
<EuiFlyoutHeader hasBorder aria-labelledby="IngestManagerSettingsFlyoutTitle">
|
||||||
|
<EuiTitle size="m">
|
||||||
|
<h2 id="IngestManagerSettingsFlyoutTitle">
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.settings.flyoutTitle"
|
||||||
|
defaultMessage="Ingest Management settings"
|
||||||
|
/>
|
||||||
|
</h2>
|
||||||
|
</EuiTitle>
|
||||||
|
</EuiFlyoutHeader>
|
||||||
|
<EuiFlyoutBody>{body}</EuiFlyoutBody>
|
||||||
|
<EuiFlyoutFooter>
|
||||||
|
<EuiFlexGroup justifyContent="spaceBetween">
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<EuiButtonEmpty iconType="cross" onClick={onClose} flush="left">
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.settings.cancelButtonLabel"
|
||||||
|
defaultMessage="Cancel"
|
||||||
|
/>
|
||||||
|
</EuiButtonEmpty>
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<EuiButton onClick={onSubmit} iconType="save">
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.settings.saveButtonLabel"
|
||||||
|
defaultMessage="Save settings"
|
||||||
|
/>
|
||||||
|
</EuiButton>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
</EuiFlyoutFooter>
|
||||||
|
</EuiFlyout>
|
||||||
|
);
|
||||||
|
};
|
|
@ -20,5 +20,27 @@ export function useInput(defaultValue = '') {
|
||||||
clear: () => {
|
clear: () => {
|
||||||
setValue('');
|
setValue('');
|
||||||
},
|
},
|
||||||
|
setValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useComboInput(defaultValue = []) {
|
||||||
|
const [value, setValue] = React.useState<string[]>(defaultValue);
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
selectedOptions: value.map((val: string) => ({ label: val })),
|
||||||
|
onCreateOption: (newVal: any) => {
|
||||||
|
setValue([...value, newVal]);
|
||||||
|
},
|
||||||
|
onChange: (newVals: any[]) => {
|
||||||
|
setValue(newVals.map(val => val.label));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value,
|
||||||
|
clear: () => {
|
||||||
|
setValue([]);
|
||||||
|
},
|
||||||
|
setValue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,3 +10,5 @@ export * from './data_stream';
|
||||||
export * from './agents';
|
export * from './agents';
|
||||||
export * from './enrollment_api_keys';
|
export * from './enrollment_api_keys';
|
||||||
export * from './epm';
|
export * from './epm';
|
||||||
|
export * from './outputs';
|
||||||
|
export * from './settings';
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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 { sendRequest, useRequest } from './use_request';
|
||||||
|
import { outputRoutesService } from '../../services';
|
||||||
|
import { PutOutputRequest, GetOutputsResponse } from '../../types';
|
||||||
|
|
||||||
|
export function useGetOutputs() {
|
||||||
|
return useRequest<GetOutputsResponse>({
|
||||||
|
method: 'get',
|
||||||
|
path: outputRoutesService.getListPath(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sendPutOutput(outputId: string, body: PutOutputRequest['body']) {
|
||||||
|
return sendRequest({
|
||||||
|
method: 'put',
|
||||||
|
path: outputRoutesService.getUpdatePath(outputId),
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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 { sendRequest, useRequest } from './use_request';
|
||||||
|
import { settingsRoutesService } from '../../services';
|
||||||
|
import { PutSettingsResponse, PutSettingsRequest, GetSettingsResponse } from '../../types';
|
||||||
|
|
||||||
|
export function useGetSettings() {
|
||||||
|
return useRequest<GetSettingsResponse>({
|
||||||
|
method: 'get',
|
||||||
|
path: settingsRoutesService.getInfoPath(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sendPutSettings(body: PutSettingsRequest['body']) {
|
||||||
|
return sendRequest<PutSettingsResponse>({
|
||||||
|
method: 'put',
|
||||||
|
path: settingsRoutesService.getUpdatePath(),
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
}
|
|
@ -5,10 +5,10 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui';
|
import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiButtonEmpty } from '@elastic/eui';
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
import { Section } from '../sections';
|
import { Section } from '../sections';
|
||||||
import { AlphaMessaging } from '../components';
|
import { AlphaMessaging, SettingFlyout } from '../components';
|
||||||
import { useLink, useConfig } from '../hooks';
|
import { useLink, useConfig } from '../hooks';
|
||||||
import { EPM_PATH, FLEET_PATH, AGENT_CONFIG_PATH, DATA_STREAM_PATH } from '../constants';
|
import { EPM_PATH, FLEET_PATH, AGENT_CONFIG_PATH, DATA_STREAM_PATH } from '../constants';
|
||||||
|
|
||||||
|
@ -35,59 +35,79 @@ const Nav = styled.nav`
|
||||||
|
|
||||||
export const DefaultLayout: React.FunctionComponent<Props> = ({ section, children }) => {
|
export const DefaultLayout: React.FunctionComponent<Props> = ({ section, children }) => {
|
||||||
const { epm, fleet } = useConfig();
|
const { epm, fleet } = useConfig();
|
||||||
|
|
||||||
|
const [isSettingsFlyoutOpen, setIsSettingsFlyoutOpen] = React.useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<>
|
||||||
<Nav>
|
{isSettingsFlyoutOpen && (
|
||||||
<EuiFlexGroup gutterSize="l" alignItems="center">
|
<SettingFlyout
|
||||||
<EuiFlexItem grow={false}>
|
onClose={() => {
|
||||||
<EuiIcon type="savedObjectsApp" size="l" />
|
setIsSettingsFlyoutOpen(false);
|
||||||
</EuiFlexItem>
|
}}
|
||||||
<EuiFlexItem>
|
/>
|
||||||
<EuiTabs display="condensed">
|
)}
|
||||||
<EuiTab isSelected={section === 'overview'} href={useLink()}>
|
<Container>
|
||||||
|
<Nav>
|
||||||
|
<EuiFlexGroup gutterSize="l" alignItems="center">
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<EuiIcon type="savedObjectsApp" size="l" />
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem>
|
||||||
|
<EuiTabs display="condensed">
|
||||||
|
<EuiTab isSelected={section === 'overview'} href={useLink()}>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.appNavigation.overviewLinkText"
|
||||||
|
defaultMessage="Overview"
|
||||||
|
/>
|
||||||
|
</EuiTab>
|
||||||
|
<EuiTab
|
||||||
|
isSelected={section === 'epm'}
|
||||||
|
href={useLink(EPM_PATH)}
|
||||||
|
disabled={!epm?.enabled}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.appNavigation.epmLinkText"
|
||||||
|
defaultMessage="Integrations"
|
||||||
|
/>
|
||||||
|
</EuiTab>
|
||||||
|
<EuiTab isSelected={section === 'agent_config'} href={useLink(AGENT_CONFIG_PATH)}>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.appNavigation.configurationsLinkText"
|
||||||
|
defaultMessage="Configurations"
|
||||||
|
/>
|
||||||
|
</EuiTab>
|
||||||
|
<EuiTab
|
||||||
|
isSelected={section === 'fleet'}
|
||||||
|
href={useLink(FLEET_PATH)}
|
||||||
|
disabled={!fleet?.enabled}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.appNavigation.fleetLinkText"
|
||||||
|
defaultMessage="Fleet"
|
||||||
|
/>
|
||||||
|
</EuiTab>
|
||||||
|
<EuiTab isSelected={section === 'data_stream'} href={useLink(DATA_STREAM_PATH)}>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ingestManager.appNavigation.dataStreamsLinkText"
|
||||||
|
defaultMessage="Data streams"
|
||||||
|
/>
|
||||||
|
</EuiTab>
|
||||||
|
</EuiTabs>
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<EuiButtonEmpty iconType="gear" onClick={() => setIsSettingsFlyoutOpen(true)}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="xpack.ingestManager.appNavigation.overviewLinkText"
|
id="xpack.ingestManager.appNavigation.settingsButton"
|
||||||
defaultMessage="Overview"
|
defaultMessage="General settings"
|
||||||
/>
|
/>
|
||||||
</EuiTab>
|
</EuiButtonEmpty>
|
||||||
<EuiTab
|
</EuiFlexItem>
|
||||||
isSelected={section === 'epm'}
|
</EuiFlexGroup>
|
||||||
href={useLink(EPM_PATH)}
|
</Nav>
|
||||||
disabled={!epm?.enabled}
|
{children}
|
||||||
>
|
<AlphaMessaging />
|
||||||
<FormattedMessage
|
</Container>
|
||||||
id="xpack.ingestManager.appNavigation.epmLinkText"
|
</>
|
||||||
defaultMessage="Integrations"
|
|
||||||
/>
|
|
||||||
</EuiTab>
|
|
||||||
<EuiTab isSelected={section === 'agent_config'} href={useLink(AGENT_CONFIG_PATH)}>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.ingestManager.appNavigation.configurationsLinkText"
|
|
||||||
defaultMessage="Configurations"
|
|
||||||
/>
|
|
||||||
</EuiTab>
|
|
||||||
<EuiTab
|
|
||||||
isSelected={section === 'fleet'}
|
|
||||||
href={useLink(FLEET_PATH)}
|
|
||||||
disabled={!fleet?.enabled}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.ingestManager.appNavigation.fleetLinkText"
|
|
||||||
defaultMessage="Fleet"
|
|
||||||
/>
|
|
||||||
</EuiTab>
|
|
||||||
<EuiTab isSelected={section === 'data_stream'} href={useLink(DATA_STREAM_PATH)}>
|
|
||||||
<FormattedMessage
|
|
||||||
id="xpack.ingestManager.appNavigation.dataStreamsLinkText"
|
|
||||||
defaultMessage="Data streams"
|
|
||||||
/>
|
|
||||||
</EuiTab>
|
|
||||||
</EuiTabs>
|
|
||||||
</EuiFlexItem>
|
|
||||||
</EuiFlexGroup>
|
|
||||||
</Nav>
|
|
||||||
{children}
|
|
||||||
<AlphaMessaging />
|
|
||||||
</Container>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,8 @@ export {
|
||||||
enrollmentAPIKeyRouteService,
|
enrollmentAPIKeyRouteService,
|
||||||
epmRouteService,
|
epmRouteService,
|
||||||
setupRouteService,
|
setupRouteService,
|
||||||
|
outputRoutesService,
|
||||||
|
settingsRoutesService,
|
||||||
packageToConfigDatasourceInputs,
|
packageToConfigDatasourceInputs,
|
||||||
storedDatasourceToAgentDatasource,
|
storedDatasourceToAgentDatasource,
|
||||||
AgentStatusKueryHelper,
|
AgentStatusKueryHelper,
|
||||||
|
|
|
@ -17,6 +17,7 @@ export {
|
||||||
DatasourceInput,
|
DatasourceInput,
|
||||||
DatasourceInputStream,
|
DatasourceInputStream,
|
||||||
DatasourceConfigRecordEntry,
|
DatasourceConfigRecordEntry,
|
||||||
|
Output,
|
||||||
DataStream,
|
DataStream,
|
||||||
// API schemas - Agent Config
|
// API schemas - Agent Config
|
||||||
GetAgentConfigsResponse,
|
GetAgentConfigsResponse,
|
||||||
|
@ -48,6 +49,14 @@ export {
|
||||||
GetEnrollmentAPIKeysResponse,
|
GetEnrollmentAPIKeysResponse,
|
||||||
GetEnrollmentAPIKeysRequest,
|
GetEnrollmentAPIKeysRequest,
|
||||||
GetOneEnrollmentAPIKeyResponse,
|
GetOneEnrollmentAPIKeyResponse,
|
||||||
|
// API schemas - Outputs
|
||||||
|
GetOutputsResponse,
|
||||||
|
PutOutputRequest,
|
||||||
|
PutOutputResponse,
|
||||||
|
// API schemas - Settings
|
||||||
|
GetSettingsResponse,
|
||||||
|
PutSettingsRequest,
|
||||||
|
PutSettingsResponse,
|
||||||
// EPM types
|
// EPM types
|
||||||
AssetReference,
|
AssetReference,
|
||||||
AssetsGroupedByServiceByType,
|
AssetsGroupedByServiceByType,
|
||||||
|
|
|
@ -19,7 +19,9 @@ export {
|
||||||
FLEET_SETUP_API_ROUTES,
|
FLEET_SETUP_API_ROUTES,
|
||||||
ENROLLMENT_API_KEY_ROUTES,
|
ENROLLMENT_API_KEY_ROUTES,
|
||||||
INSTALL_SCRIPT_API_ROUTES,
|
INSTALL_SCRIPT_API_ROUTES,
|
||||||
|
OUTPUT_API_ROUTES,
|
||||||
SETUP_API_ROUTE,
|
SETUP_API_ROUTE,
|
||||||
|
SETTINGS_API_ROUTES,
|
||||||
// Saved object types
|
// Saved object types
|
||||||
AGENT_SAVED_OBJECT_TYPE,
|
AGENT_SAVED_OBJECT_TYPE,
|
||||||
AGENT_EVENT_SAVED_OBJECT_TYPE,
|
AGENT_EVENT_SAVED_OBJECT_TYPE,
|
||||||
|
@ -30,6 +32,7 @@ export {
|
||||||
PACKAGES_SAVED_OBJECT_TYPE,
|
PACKAGES_SAVED_OBJECT_TYPE,
|
||||||
INDEX_PATTERN_SAVED_OBJECT_TYPE,
|
INDEX_PATTERN_SAVED_OBJECT_TYPE,
|
||||||
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
|
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
|
||||||
|
GLOBAL_SETTINGS_SAVED_OBJECT_TYPE as GLOBAL_SETTINGS_SAVED_OBJET_TYPE,
|
||||||
// Defaults
|
// Defaults
|
||||||
DEFAULT_AGENT_CONFIG,
|
DEFAULT_AGENT_CONFIG,
|
||||||
DEFAULT_OUTPUT,
|
DEFAULT_OUTPUT,
|
||||||
|
|
|
@ -39,6 +39,8 @@ import {
|
||||||
registerAgentRoutes,
|
registerAgentRoutes,
|
||||||
registerEnrollmentApiKeyRoutes,
|
registerEnrollmentApiKeyRoutes,
|
||||||
registerInstallScriptRoutes,
|
registerInstallScriptRoutes,
|
||||||
|
registerOutputRoutes,
|
||||||
|
registerSettingsRoutes,
|
||||||
} from './routes';
|
} from './routes';
|
||||||
|
|
||||||
import { IngestManagerConfigType } from '../common';
|
import { IngestManagerConfigType } from '../common';
|
||||||
|
@ -150,6 +152,8 @@ export class IngestManagerPlugin
|
||||||
// Register routes
|
// Register routes
|
||||||
registerAgentConfigRoutes(router);
|
registerAgentConfigRoutes(router);
|
||||||
registerDatasourceRoutes(router);
|
registerDatasourceRoutes(router);
|
||||||
|
registerOutputRoutes(router);
|
||||||
|
registerSettingsRoutes(router);
|
||||||
registerDataStreamRoutes(router);
|
registerDataStreamRoutes(router);
|
||||||
|
|
||||||
// Conditional routes
|
// Conditional routes
|
||||||
|
|
|
@ -11,3 +11,5 @@ export { registerRoutes as registerSetupRoutes } from './setup';
|
||||||
export { registerRoutes as registerAgentRoutes } from './agent';
|
export { registerRoutes as registerAgentRoutes } from './agent';
|
||||||
export { registerRoutes as registerEnrollmentApiKeyRoutes } from './enrollment_api_key';
|
export { registerRoutes as registerEnrollmentApiKeyRoutes } from './enrollment_api_key';
|
||||||
export { registerRoutes as registerInstallScriptRoutes } from './install_script';
|
export { registerRoutes as registerInstallScriptRoutes } from './install_script';
|
||||||
|
export { registerRoutes as registerOutputRoutes } from './output';
|
||||||
|
export { registerRoutes as registerSettingsRoutes } from './settings';
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* 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 { RequestHandler } from 'src/core/server';
|
||||||
|
import { TypeOf } from '@kbn/config-schema';
|
||||||
|
import { GetOneOutputRequestSchema, PutOutputRequestSchema } from '../../types';
|
||||||
|
import { GetOneOutputResponse, GetOutputsResponse } from '../../../common';
|
||||||
|
import { outputService } from '../../services/output';
|
||||||
|
|
||||||
|
export const getOutputsHandler: RequestHandler = async (context, request, response) => {
|
||||||
|
const soClient = context.core.savedObjects.client;
|
||||||
|
try {
|
||||||
|
const outputs = await outputService.list(soClient);
|
||||||
|
|
||||||
|
const body: GetOutputsResponse = {
|
||||||
|
items: outputs.items,
|
||||||
|
page: outputs.page,
|
||||||
|
perPage: outputs.perPage,
|
||||||
|
total: outputs.total,
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return response.ok({ body });
|
||||||
|
} catch (e) {
|
||||||
|
return response.customError({
|
||||||
|
statusCode: 500,
|
||||||
|
body: { message: e.message },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getOneOuputHandler: RequestHandler<TypeOf<
|
||||||
|
typeof GetOneOutputRequestSchema.params
|
||||||
|
>> = async (context, request, response) => {
|
||||||
|
const soClient = context.core.savedObjects.client;
|
||||||
|
try {
|
||||||
|
const output = await outputService.get(soClient, request.params.outputId);
|
||||||
|
|
||||||
|
const body: GetOneOutputResponse = {
|
||||||
|
item: output,
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return response.ok({ body });
|
||||||
|
} catch (e) {
|
||||||
|
if (e.isBoom && e.output.statusCode === 404) {
|
||||||
|
return response.notFound({
|
||||||
|
body: { message: `Output ${request.params.outputId} not found` },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.customError({
|
||||||
|
statusCode: 500,
|
||||||
|
body: { message: e.message },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const putOuputHandler: RequestHandler<
|
||||||
|
TypeOf<typeof PutOutputRequestSchema.params>,
|
||||||
|
undefined,
|
||||||
|
TypeOf<typeof PutOutputRequestSchema.body>
|
||||||
|
> = async (context, request, response) => {
|
||||||
|
const soClient = context.core.savedObjects.client;
|
||||||
|
try {
|
||||||
|
await outputService.update(soClient, request.params.outputId, request.body);
|
||||||
|
const output = await outputService.get(soClient, request.params.outputId);
|
||||||
|
|
||||||
|
const body: GetOneOutputResponse = {
|
||||||
|
item: output,
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return response.ok({ body });
|
||||||
|
} catch (e) {
|
||||||
|
if (e.isBoom && e.output.statusCode === 404) {
|
||||||
|
return response.notFound({
|
||||||
|
body: { message: `Output ${request.params.outputId} not found` },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.customError({
|
||||||
|
statusCode: 500,
|
||||||
|
body: { message: e.message },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
41
x-pack/plugins/ingest_manager/server/routes/output/index.ts
Normal file
41
x-pack/plugins/ingest_manager/server/routes/output/index.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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 { IRouter } from 'src/core/server';
|
||||||
|
import { PLUGIN_ID, OUTPUT_API_ROUTES } from '../../constants';
|
||||||
|
import { getOneOuputHandler, getOutputsHandler, putOuputHandler } from './handler';
|
||||||
|
import {
|
||||||
|
GetOneOutputRequestSchema,
|
||||||
|
GetOutputsRequestSchema,
|
||||||
|
PutOutputRequestSchema,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
|
export const registerRoutes = (router: IRouter) => {
|
||||||
|
router.get(
|
||||||
|
{
|
||||||
|
path: OUTPUT_API_ROUTES.LIST_PATTERN,
|
||||||
|
validate: GetOutputsRequestSchema,
|
||||||
|
options: { tags: [`access:${PLUGIN_ID}-read`] },
|
||||||
|
},
|
||||||
|
getOutputsHandler
|
||||||
|
);
|
||||||
|
router.get(
|
||||||
|
{
|
||||||
|
path: OUTPUT_API_ROUTES.INFO_PATTERN,
|
||||||
|
validate: GetOneOutputRequestSchema,
|
||||||
|
options: { tags: [`access:${PLUGIN_ID}-read`] },
|
||||||
|
},
|
||||||
|
getOneOuputHandler
|
||||||
|
);
|
||||||
|
router.put(
|
||||||
|
{
|
||||||
|
path: OUTPUT_API_ROUTES.UPDATE_PATTERN,
|
||||||
|
validate: PutOutputRequestSchema,
|
||||||
|
options: { tags: [`access:${PLUGIN_ID}-read`] },
|
||||||
|
},
|
||||||
|
putOuputHandler
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* 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 { IRouter, RequestHandler } from 'src/core/server';
|
||||||
|
import { TypeOf } from '@kbn/config-schema';
|
||||||
|
import { PLUGIN_ID, SETTINGS_API_ROUTES } from '../../constants';
|
||||||
|
import { PutSettingsRequestSchema, GetSettingsRequestSchema } from '../../types';
|
||||||
|
|
||||||
|
import { settingsService } from '../../services';
|
||||||
|
|
||||||
|
export const getSettingsHandler: RequestHandler = async (context, request, response) => {
|
||||||
|
const soClient = context.core.savedObjects.client;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const settings = await settingsService.getSettings(soClient);
|
||||||
|
const body = {
|
||||||
|
success: true,
|
||||||
|
item: settings,
|
||||||
|
};
|
||||||
|
return response.ok({ body });
|
||||||
|
} catch (e) {
|
||||||
|
if (e.isBoom && e.output.statusCode === 404) {
|
||||||
|
return response.notFound({
|
||||||
|
body: { message: `Setings not found` },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.customError({
|
||||||
|
statusCode: 500,
|
||||||
|
body: { message: e.message },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const putSettingsHandler: RequestHandler<
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
TypeOf<typeof PutSettingsRequestSchema.body>
|
||||||
|
> = async (context, request, response) => {
|
||||||
|
const soClient = context.core.savedObjects.client;
|
||||||
|
try {
|
||||||
|
const settings = await settingsService.saveSettings(soClient, request.body);
|
||||||
|
const body = {
|
||||||
|
success: true,
|
||||||
|
item: settings,
|
||||||
|
};
|
||||||
|
return response.ok({ body });
|
||||||
|
} catch (e) {
|
||||||
|
if (e.isBoom && e.output.statusCode === 404) {
|
||||||
|
return response.notFound({
|
||||||
|
body: { message: `Setings not found` },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.customError({
|
||||||
|
statusCode: 500,
|
||||||
|
body: { message: e.message },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerRoutes = (router: IRouter) => {
|
||||||
|
router.get(
|
||||||
|
{
|
||||||
|
path: SETTINGS_API_ROUTES.INFO_PATTERN,
|
||||||
|
validate: GetSettingsRequestSchema,
|
||||||
|
options: { tags: [`access:${PLUGIN_ID}-read`] },
|
||||||
|
},
|
||||||
|
getSettingsHandler
|
||||||
|
);
|
||||||
|
router.put(
|
||||||
|
{
|
||||||
|
path: SETTINGS_API_ROUTES.UPDATE_PATTERN,
|
||||||
|
validate: PutSettingsRequestSchema,
|
||||||
|
options: { tags: [`access:${PLUGIN_ID}-all`] },
|
||||||
|
},
|
||||||
|
putSettingsHandler
|
||||||
|
);
|
||||||
|
};
|
|
@ -15,6 +15,7 @@ import {
|
||||||
AGENT_EVENT_SAVED_OBJECT_TYPE,
|
AGENT_EVENT_SAVED_OBJECT_TYPE,
|
||||||
AGENT_ACTION_SAVED_OBJECT_TYPE,
|
AGENT_ACTION_SAVED_OBJECT_TYPE,
|
||||||
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
|
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
|
||||||
|
GLOBAL_SETTINGS_SAVED_OBJET_TYPE,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -22,7 +23,24 @@ import {
|
||||||
*
|
*
|
||||||
* Please update typings in `/common/types` if mappings are updated.
|
* Please update typings in `/common/types` if mappings are updated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const savedObjectTypes: { [key: string]: SavedObjectsType } = {
|
const savedObjectTypes: { [key: string]: SavedObjectsType } = {
|
||||||
|
[GLOBAL_SETTINGS_SAVED_OBJET_TYPE]: {
|
||||||
|
name: GLOBAL_SETTINGS_SAVED_OBJET_TYPE,
|
||||||
|
hidden: false,
|
||||||
|
namespaceType: 'agnostic',
|
||||||
|
management: {
|
||||||
|
importableAndExportable: false,
|
||||||
|
},
|
||||||
|
mappings: {
|
||||||
|
properties: {
|
||||||
|
agent_auto_upgrade: { type: 'keyword' },
|
||||||
|
package_auto_upgrade: { type: 'keyword' },
|
||||||
|
kibana_url: { type: 'keyword' },
|
||||||
|
kibana_ca_sha256: { type: 'keyword' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
[AGENT_SAVED_OBJECT_TYPE]: {
|
[AGENT_SAVED_OBJECT_TYPE]: {
|
||||||
name: AGENT_SAVED_OBJECT_TYPE,
|
name: AGENT_SAVED_OBJECT_TYPE,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SavedObjectsClientContract } from 'kibana/server';
|
import { SavedObjectsClientContract } from 'kibana/server';
|
||||||
import { AgentStatus } from '../../common/types/models';
|
import { AgentStatus } from '../../common/types/models';
|
||||||
|
import * as settingsService from './settings';
|
||||||
export { ESIndexPatternSavedObjectService } from './es_index_pattern';
|
export { ESIndexPatternSavedObjectService } from './es_index_pattern';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,6 +36,7 @@ export interface AgentService {
|
||||||
export { datasourceService } from './datasource';
|
export { datasourceService } from './datasource';
|
||||||
export { agentConfigService } from './agent_config';
|
export { agentConfigService } from './agent_config';
|
||||||
export { outputService } from './output';
|
export { outputService } from './output';
|
||||||
|
export { settingsService };
|
||||||
|
|
||||||
// Plugin services
|
// Plugin services
|
||||||
export { appContextService } from './app_context';
|
export { appContextService } from './app_context';
|
||||||
|
|
|
@ -95,6 +95,34 @@ class OutputService {
|
||||||
...outputSO.attributes,
|
...outputSO.attributes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async update(soClient: SavedObjectsClientContract, id: string, data: Partial<Output>) {
|
||||||
|
const outputSO = await soClient.update<Output>(SAVED_OBJECT_TYPE, id, data);
|
||||||
|
|
||||||
|
if (outputSO.error) {
|
||||||
|
throw new Error(outputSO.error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async list(soClient: SavedObjectsClientContract) {
|
||||||
|
const outputs = await soClient.find<Output>({
|
||||||
|
type: SAVED_OBJECT_TYPE,
|
||||||
|
page: 1,
|
||||||
|
perPage: 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
items: outputs.saved_objects.map<Output>(outputSO => {
|
||||||
|
return {
|
||||||
|
id: outputSO.id,
|
||||||
|
...outputSO.attributes,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
total: outputs.total,
|
||||||
|
page: 1,
|
||||||
|
perPage: 1000,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const outputService = new OutputService();
|
export const outputService = new OutputService();
|
||||||
|
|
57
x-pack/plugins/ingest_manager/server/services/settings.ts
Normal file
57
x-pack/plugins/ingest_manager/server/services/settings.ts
Normal file
|
@ -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 Boom from 'boom';
|
||||||
|
import { SavedObjectsClientContract } from 'kibana/server';
|
||||||
|
import { GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, SettingsSOAttributes, Settings } from '../../common';
|
||||||
|
|
||||||
|
export async function getSettings(soClient: SavedObjectsClientContract): Promise<Settings> {
|
||||||
|
const res = await soClient.find<SettingsSOAttributes>({
|
||||||
|
type: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.total === 0) {
|
||||||
|
throw Boom.notFound('Global settings not found');
|
||||||
|
}
|
||||||
|
const settingsSo = res.saved_objects[0];
|
||||||
|
return {
|
||||||
|
id: settingsSo.id,
|
||||||
|
...settingsSo.attributes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveSettings(
|
||||||
|
soClient: SavedObjectsClientContract,
|
||||||
|
newData: Partial<Omit<Settings, 'id'>>
|
||||||
|
): Promise<Settings> {
|
||||||
|
try {
|
||||||
|
const settings = await getSettings(soClient);
|
||||||
|
|
||||||
|
const res = await soClient.update<SettingsSOAttributes>(
|
||||||
|
GLOBAL_SETTINGS_SAVED_OBJECT_TYPE,
|
||||||
|
settings.id,
|
||||||
|
newData
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: settings.id,
|
||||||
|
...res.attributes,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
if (e.isBoom && e.output.statusCode === 404) {
|
||||||
|
const res = await soClient.create<SettingsSOAttributes>(
|
||||||
|
GLOBAL_SETTINGS_SAVED_OBJECT_TYPE,
|
||||||
|
newData
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: res.id,
|
||||||
|
...res.attributes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ import {
|
||||||
import { getPackageInfo } from './epm/packages';
|
import { getPackageInfo } from './epm/packages';
|
||||||
import { datasourceService } from './datasource';
|
import { datasourceService } from './datasource';
|
||||||
import { generateEnrollmentAPIKey } from './api_keys';
|
import { generateEnrollmentAPIKey } from './api_keys';
|
||||||
|
import { settingsService } from '.';
|
||||||
|
import { appContextService } from './app_context';
|
||||||
|
|
||||||
const FLEET_ENROLL_USERNAME = 'fleet_enroll';
|
const FLEET_ENROLL_USERNAME = 'fleet_enroll';
|
||||||
const FLEET_ENROLL_ROLE = 'fleet_enroll';
|
const FLEET_ENROLL_ROLE = 'fleet_enroll';
|
||||||
|
@ -34,6 +36,17 @@ export async function setupIngestManager(
|
||||||
ensureInstalledDefaultPackages(soClient, callCluster),
|
ensureInstalledDefaultPackages(soClient, callCluster),
|
||||||
outputService.ensureDefaultOutput(soClient),
|
outputService.ensureDefaultOutput(soClient),
|
||||||
agentConfigService.ensureDefaultAgentConfig(soClient),
|
agentConfigService.ensureDefaultAgentConfig(soClient),
|
||||||
|
settingsService.getSettings(soClient).catch((e: any) => {
|
||||||
|
if (e.isBoom && e.output.statusCode === 404) {
|
||||||
|
return settingsService.saveSettings(soClient, {
|
||||||
|
agent_auto_upgrade: true,
|
||||||
|
package_auto_upgrade: true,
|
||||||
|
kibana_url: appContextService.getConfig()?.fleet?.kibana?.host,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(e);
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// ensure default packages are added to the default conifg
|
// ensure default packages are added to the default conifg
|
||||||
|
|
|
@ -50,6 +50,8 @@ export {
|
||||||
DefaultPackages,
|
DefaultPackages,
|
||||||
TemplateRef,
|
TemplateRef,
|
||||||
IndexTemplateMappings,
|
IndexTemplateMappings,
|
||||||
|
Settings,
|
||||||
|
SettingsSOAttributes,
|
||||||
} from '../../common';
|
} from '../../common';
|
||||||
|
|
||||||
export type CallESAsCurrentUser = ScopedClusterClient['callAsCurrentUser'];
|
export type CallESAsCurrentUser = ScopedClusterClient['callAsCurrentUser'];
|
||||||
|
|
|
@ -10,3 +10,5 @@ export * from './datasource';
|
||||||
export * from './epm';
|
export * from './epm';
|
||||||
export * from './enrollment_api_key';
|
export * from './enrollment_api_key';
|
||||||
export * from './install_script';
|
export * from './install_script';
|
||||||
|
export * from './output';
|
||||||
|
export * from './settings';
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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 { schema } from '@kbn/config-schema';
|
||||||
|
|
||||||
|
export const GetOneOutputRequestSchema = {
|
||||||
|
params: schema.object({
|
||||||
|
outputId: schema.string(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GetOutputsRequestSchema = {};
|
||||||
|
|
||||||
|
export const PutOutputRequestSchema = {
|
||||||
|
params: schema.object({
|
||||||
|
outputId: schema.string(),
|
||||||
|
}),
|
||||||
|
body: schema.object({
|
||||||
|
hosts: schema.maybe(schema.arrayOf(schema.string())),
|
||||||
|
ca_sha256: schema.maybe(schema.string()),
|
||||||
|
}),
|
||||||
|
};
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* 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 { schema } from '@kbn/config-schema';
|
||||||
|
|
||||||
|
export const GetSettingsRequestSchema = {};
|
||||||
|
|
||||||
|
export const PutSettingsRequestSchema = {
|
||||||
|
body: schema.object({
|
||||||
|
agent_auto_upgrade: schema.maybe(schema.boolean()),
|
||||||
|
package_auto_upgrade: schema.maybe(schema.boolean()),
|
||||||
|
kibana_url: schema.maybe(schema.string()),
|
||||||
|
kibana_ca_sha256: schema.maybe(schema.string()),
|
||||||
|
}),
|
||||||
|
};
|
Loading…
Reference in a new issue