[Fleet] Add ability to set a proxy for agent binary source (#164168)

## Summary

Closes #162862 

Add a proxy selector for agent download sources. 

Selecting a proxy will set the agent.download.proxy_url field on the
agent policy (this can be checked in the "view full agent policy"
flyout). I have marked this functionality as beta as we currently can
only use the URL of the proxy, not the certificates or headers.

Editing a proxy should automatically update all associated policies
which use download sources with that proxy.

Deleting a proxy should remove the proxy from all associated policies. 

<img width="1789" alt="Screenshot 2023-08-17 at 14 41 58"
src="7b1afb40-4b89-4509-89df-9850627d7257">


Verifying the field is set...


<img width="1788" alt="Screenshot 2023-08-17 at 14 43 38"
src="81316dd1-dc8f-4120-9bbc-9e96e522ceda">


### Checklist

Delete any items that are not applicable to this PR.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [x] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Mark Hopkin 2023-08-22 09:12:20 +01:00 committed by GitHub
parent 4b1d833aee
commit ce93a1f871
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 6 deletions

View file

@ -40,6 +40,7 @@ export interface PostDownloadSourceRequest {
name: string;
host: string;
is_default?: boolean;
proxy_id?: string | null;
};
}

View file

@ -16,7 +16,7 @@ function renderFlyout(downloadSource?: DownloadSource) {
const renderer = createFleetTestRendererMock();
const comp = renderer.render(
<EditDownloadSourceFlyout downloadSource={downloadSource} onClose={() => {}} />
<EditDownloadSourceFlyout downloadSource={downloadSource} onClose={() => {}} proxies={[]} />
);
return { comp };

View file

@ -5,9 +5,10 @@
* 2.0.
*/
import React from 'react';
import React, { useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiComboBox,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutHeader,
@ -23,10 +24,11 @@ import {
EuiLink,
EuiSwitch,
EuiSpacer,
EuiBetaBadge,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { DownloadSource } from '../../../../types';
import type { DownloadSource, FleetProxy } from '../../../../types';
import { FLYOUT_MAX_WIDTH } from '../../constants';
import { useBreadcrumbs, useStartServices } from '../../../../hooks';
@ -35,17 +37,22 @@ import { useDowloadSourceFlyoutForm } from './use_download_source_flyout_form';
export interface EditDownloadSourceFlyoutProps {
downloadSource?: DownloadSource;
onClose: () => void;
proxies: FleetProxy[];
}
export const EditDownloadSourceFlyout: React.FunctionComponent<EditDownloadSourceFlyoutProps> = ({
onClose,
downloadSource,
proxies,
}) => {
useBreadcrumbs('settings');
const form = useDowloadSourceFlyoutForm(onClose, downloadSource);
const inputs = form.inputs;
const { docLinks } = useStartServices();
const proxiesOptions = useMemo(
() => proxies.map((proxy) => ({ value: proxy.id, label: proxy.name })),
[proxies]
);
return (
<EuiFlyout maxWidth={FLYOUT_MAX_WIDTH} onClose={onClose}>
<EuiFlyoutHeader hasBorder={true}>
@ -130,6 +137,57 @@ export const EditDownloadSourceFlyout: React.FunctionComponent<EditDownloadSourc
)}
/>
</EuiFormRow>
<EuiFormRow
fullWidth
label={
<FormattedMessage
id="xpack.fleet.settings.editDownloadSourcesFlyout.proxyIdLabel"
defaultMessage="Proxy {badge}"
values={{
badge: (
<EuiBetaBadge
size="s"
className="eui-alignTop"
label={i18n.translate(
'xpack.fleet.settings.editDownloadSourcesFlyout.proxyIdBetaBadge',
{
defaultMessage: 'Beta',
}
)}
/>
),
}}
/>
}
helpText={
<FormattedMessage
id="xpack.fleet.settings.editDownloadSourcesFlyout.proxyInputDescription"
defaultMessage="Proxy used for accessing the download source. Currently only the proxy URL is used, headers and certificates are not supported."
/>
}
>
<EuiComboBox
fullWidth
data-test-subj="settingsOutputsFlyout.proxyIdInput"
{...inputs.proxyIdInput.props}
onChange={(options) => inputs.proxyIdInput.setValue(options?.[0]?.value ?? '')}
selectedOptions={
inputs.proxyIdInput.value !== ''
? proxiesOptions.filter((option) => option.value === inputs.proxyIdInput.value)
: []
}
options={proxiesOptions}
singleSelection={{ asPlainText: true }}
isDisabled={inputs.proxyIdInput.props.disabled}
isClearable={true}
placeholder={i18n.translate(
'xpack.fleet.settings.editDownloadSourcesFlyout.proxyIdPlaceholder',
{
defaultMessage: 'Select proxy',
}
)}
/>
</EuiFormRow>
<EuiSpacer size="m" />
<EuiFormRow fullWidth {...inputs.defaultDownloadSourceInput.formRowProps}>
<EuiSwitch

View file

@ -35,10 +35,13 @@ export function useDowloadSourceFlyoutForm(onSuccess: () => void, downloadSource
const hostInput = useInput(downloadSource?.host ?? '', validateHost);
const proxyIdInput = useInput(downloadSource?.proxy_id ?? '', () => undefined);
const inputs = {
nameInput,
hostInput,
defaultDownloadSourceInput,
proxyIdInput,
};
const hasChanged = Object.values(inputs).some((input) => input.hasChanged);
@ -61,6 +64,7 @@ export function useDowloadSourceFlyoutForm(onSuccess: () => void, downloadSource
name: nameInput.value.trim(),
host: hostInput.value.trim(),
is_default: defaultDownloadSourceInput.value,
proxy_id: proxyIdInput.value || null,
};
if (downloadSource) {
@ -100,6 +104,7 @@ export function useDowloadSourceFlyoutForm(onSuccess: () => void, downloadSource
nameInput.value,
notifications.toasts,
onSuccess,
proxyIdInput.value,
validate,
]);

View file

@ -52,7 +52,7 @@ export const FleetProxiesSection: React.FunctionComponent<FleetProxiesSectionPro
<EuiText color="subdued" size="m">
<FormattedMessage
id="xpack.fleet.settings.fleetProxiesSection.subtitle"
defaultMessage="Specify any proxy URLs to be used in Fleet servers or Outputs."
defaultMessage="Specify any proxy URLs to be used in Fleet servers, Outputs or Agent binary download sources."
/>
</EuiText>
<EuiSpacer size="m" />

View file

@ -166,7 +166,10 @@ export const SettingsApp = withConfirmModalProvider(() => {
</Route>
<Route path={FLEET_ROUTING_PATHS.settings_create_download_sources}>
<EuiPortal>
<EditDownloadSourceFlyout onClose={onCloseCallback} />
<EditDownloadSourceFlyout
onClose={onCloseCallback}
proxies={proxies?.data?.items || []}
/>
</EuiPortal>
</Route>
<Route path={FLEET_ROUTING_PATHS.settings_edit_download_sources}>
@ -183,6 +186,7 @@ export const SettingsApp = withConfirmModalProvider(() => {
<EditDownloadSourceFlyout
onClose={onCloseCallback}
downloadSource={downloadSource}
proxies={proxies?.data?.items || []}
/>
</EuiPortal>
);