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

[Uptime] Update TLS settings #64111

Merged
merged 12 commits into from
Apr 24, 2020
1 change: 1 addition & 0 deletions x-pack/legacy/plugins/uptime/common/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { CHART_FORMAT_LIMITS } from './chart_format_limits';
export { CLIENT_DEFAULTS } from './client_defaults';
export { CONTEXT_DEFAULTS } from './context_defaults';
export * from './capabilities';
export * from './settings_defaults';
export { PLUGIN } from './plugin';
export { QUERY, STATES } from './query';
export * from './ui';
Expand Down
15 changes: 15 additions & 0 deletions x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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 { DynamicSettings } from '../runtime_types';

export const DYNAMIC_SETTINGS_DEFAULTS: DynamicSettings = {
heartbeatIndices: 'heartbeat-8*',
certificatesThresholds: {
expiration: 7,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this should be 30 days be default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d0246a7.

age: 365,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

import * as t from 'io-ts';

export const CertificatesStatesThresholdType = t.interface({
warningState: t.number,
errorState: t.number,
export const CertificatesStatesThresholdType = t.partial({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this shouldn't be partial.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense just to rename it CertStateThresholds WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

age: t.number,
expiration: t.number,
});

export const DynamicSettingsType = t.intersection([
Expand All @@ -32,11 +32,3 @@ export const DynamicSettingsSaveType = t.intersection([
export type DynamicSettings = t.TypeOf<typeof DynamicSettingsType>;
export type DynamicSettingsSaveResponse = t.TypeOf<typeof DynamicSettingsSaveType>;
export type CertificatesStatesThreshold = t.TypeOf<typeof CertificatesStatesThresholdType>;

export const defaultDynamicSettings: DynamicSettings = {
heartbeatIndices: 'heartbeat-8*',
certificatesThresholds: {
errorState: 7,
warningState: 30,
},
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('CertificateForm', () => {
onChange={jest.fn()}
formFields={{
heartbeatIndices: 'heartbeat-8*',
certificatesThresholds: { errorState: 7, warningState: 36 },
certificatesThresholds: { expiration: 7, age: 36 },
}}
fieldErrors={{}}
isDisabled={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('CertificateForm', () => {
onChange={jest.fn()}
formFields={{
heartbeatIndices: 'heartbeat-8*',
certificatesThresholds: { errorState: 7, warningState: 36 },
certificatesThresholds: { expiration: 7, age: 36 },
}}
fieldErrors={{}}
isDisabled={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,16 @@ import {
EuiFormRow,
EuiCode,
EuiFieldNumber,
EuiText,
EuiTitle,
EuiSpacer,
EuiSelect,
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { defaultDynamicSettings, DynamicSettings } from '../../../common/runtime_types';
import { DynamicSettings } from '../../../common/runtime_types';
import { selectDynamicSettings } from '../../state/selectors';

type NumStr = string | number;

export type OnFieldChangeType = (field: string, value?: NumStr) => void;
export type OnFieldChangeType = (changedValues: Partial<DynamicSettings>) => void;

export interface SettingsFormProps {
onChange: OnFieldChangeType;
Expand Down Expand Up @@ -55,15 +53,15 @@ export const CertificateExpirationForm: React.FC<SettingsFormProps> = ({
title={
<h4>
<FormattedMessage
id="xpack.uptime.sourceConfiguration.stateThresholds"
defaultMessage="Expiration State Thresholds"
id="xpack.uptime.sourceConfiguration.expirationThreshold"
defaultMessage="Expiration/Age Thresholds"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should also add that text here which got updated in ACs "Change the threshold for displaying and alerting on certificate errors. Note, this will affect any configured alerts"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this copy in 0ddd97b, modified the punctuation a bit in a1fdf46.

/>
</h4>
}
description={
<FormattedMessage
id="xpack.uptime.sourceConfiguration.stateThresholdsDescription"
defaultMessage="Set certificate expiration warning/error thresholds"
id="xpack.uptime.sourceConfiguration.certificateThresholdDescription"
defaultMessage="Set certificate expiration/age thresholds"
/>
}
>
Expand All @@ -76,38 +74,42 @@ export const CertificateExpirationForm: React.FC<SettingsFormProps> = ({
id="xpack.uptime.sourceConfiguration.errorStateDefaultValue"
defaultMessage="The default value is {defaultValue}"
values={{
defaultValue: (
<EuiCode>{defaultDynamicSettings?.certificatesThresholds?.errorState}</EuiCode>
),
defaultValue: <EuiCode>{dss.settings.certificatesThresholds?.expiration}</EuiCode>,
}}
/>
}
isInvalid={!!fieldErrors?.certificatesThresholds?.errorState}
label={
<FormattedMessage
id="xpack.uptime.sourceConfiguration.errorStateLabel"
defaultMessage="Error state"
defaultMessage="Expiration threshold"
/>
}
>
<EuiFlexGroup>
<EuiFlexItem grow={2}>
<EuiFieldNumber
data-test-subj={`error-state-threshold-input-${dss.loading ? 'loading' : 'loaded'}`}
data-test-subj={`expiration-threshold-input-${dss.loading ? 'loading' : 'loaded'}`}
fullWidth
disabled={isDisabled}
isLoading={dss.loading}
value={formFields?.certificatesThresholds?.errorState || ''}
value={formFields?.certificatesThresholds?.expiration || ''}
onChange={({ currentTarget: { value } }: any) =>
onChange(
'certificatesThresholds.errorState',
value === '' ? undefined : Number(value)
)
onChange({
certificatesThresholds: {
expiration: Number(value),
},
})
}
/>
</EuiFlexItem>
<EuiFlexItem grow={1}>
<EuiSelect options={[{ value: 'day', text: 'Days' }]} />
<EuiText>
<FormattedMessage
id="xpack.uptime.sourceConfiguration.ageLimit.units.days"
defaultMessage="Days"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
Expand All @@ -120,37 +122,40 @@ export const CertificateExpirationForm: React.FC<SettingsFormProps> = ({
id="xpack.uptime.sourceConfiguration.warningStateDefaultValue"
defaultMessage="The default value is {defaultValue}"
values={{
defaultValue: (
<EuiCode>{defaultDynamicSettings?.certificatesThresholds?.warningState}</EuiCode>
),
defaultValue: <EuiCode>{dss.settings.certificatesThresholds?.age}</EuiCode>,
}}
/>
}
isInvalid={!!fieldErrors?.certificatesThresholds?.warningState}
label={
<FormattedMessage
id="xpack.uptime.sourceConfiguration.warningStateLabel"
defaultMessage="Warning state"
defaultMessage="Age limit"
/>
}
>
<EuiFlexGroup>
<EuiFlexItem grow={2}>
<EuiFieldNumber
data-test-subj={`warning-state-threshold-input-${
dss.loading ? 'loading' : 'loaded'
}`}
data-test-subj={`age-threshold-input-${dss.loading ? 'loading' : 'loaded'}`}
fullWidth
disabled={isDisabled}
isLoading={dss.loading}
value={formFields?.certificatesThresholds?.warningState || ''}
value={formFields?.certificatesThresholds?.age || ''}
onChange={(event: any) =>
onChange('certificatesThresholds.warningState', Number(event.currentTarget.value))
onChange({
certificatesThresholds: { age: Number(event.currentTarget.value) },
})
}
/>
</EuiFlexItem>
<EuiFlexItem grow={1}>
<EuiSelect options={[{ value: 'day', text: 'Days' }]} />
<EuiText>
<FormattedMessage
id="xpack.uptime.sourceConfiguration.ageLimit.units.days"
defaultMessage="Days"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
EuiTitle,
EuiSpacer,
} from '@elastic/eui';
import { defaultDynamicSettings } from '../../../common/runtime_types';
import { selectDynamicSettings } from '../../state/selectors';
import { SettingsFormProps } from './certificate_form';

Expand Down Expand Up @@ -63,7 +62,7 @@ export const IndicesForm: React.FC<SettingsFormProps> = ({
id="xpack.uptime.sourceConfiguration.heartbeatIndicesDefaultValue"
defaultMessage="The default value is {defaultValue}"
values={{
defaultValue: <EuiCode>{defaultDynamicSettings.heartbeatIndices}</EuiCode>,
defaultValue: <EuiCode>{dss.settings.heartbeatIndices}</EuiCode>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change will display the current value? default value should come from constant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right you are, we don't want that to change!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is using defaults again now.

}}
/>
}
Expand All @@ -81,7 +80,7 @@ export const IndicesForm: React.FC<SettingsFormProps> = ({
disabled={isDisabled}
isLoading={dss.loading}
value={formFields?.heartbeatIndices || ''}
onChange={(event: any) => onChange('heartbeatIndices', event.currentTarget.value)}
onChange={(event: any) => onChange({ heartbeatIndices: event.currentTarget.value })}
/>
</EuiFormRow>
</EuiDescribedFormGroup>
Expand Down
55 changes: 15 additions & 40 deletions x-pack/legacy/plugins/uptime/public/pages/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import {
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { useDispatch, useSelector } from 'react-redux';
import { cloneDeep, isEqual, set } from 'lodash';
import { i18n } from '@kbn/i18n';
import { isEqual, merge } from 'lodash';
import { Link } from 'react-router-dom';
import { selectDynamicSettings } from '../state/selectors';
import { getDynamicSettings, setDynamicSettings } from '../state/actions/dynamic_settings';
Expand All @@ -32,14 +31,15 @@ import {
CertificateExpirationForm,
OnFieldChangeType,
} from '../components/settings/certificate_form';
import * as Translations from './translations';

const getFieldErrors = (formFields: DynamicSettings | null) => {
if (formFields) {
const blankStr = 'May not be blank';
const { certificatesThresholds, heartbeatIndices } = formFields;
const heartbeatIndErr = heartbeatIndices.match(/^\S+$/) ? '' : blankStr;
const errorStateErr = certificatesThresholds?.errorState ? null : blankStr;
const warningStateErr = certificatesThresholds?.warningState ? null : blankStr;
const errorStateErr = certificatesThresholds?.expiration ? null : blankStr;
const warningStateErr = certificatesThresholds?.age ? null : blankStr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also rename var name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized we needed to improve this, so I added a type and renamed the var usage in 59e60e8.

return {
heartbeatIndices: heartbeatIndErr,
certificatesThresholds:
Expand All @@ -57,10 +57,7 @@ const getFieldErrors = (formFields: DynamicSettings | null) => {
export const SettingsPage = () => {
const dss = useSelector(selectDynamicSettings);

const settingsBreadcrumbText = i18n.translate('xpack.uptime.settingsBreadcrumbText', {
defaultMessage: 'Settings',
});
useBreadcrumbs([{ text: settingsBreadcrumbText }]);
useBreadcrumbs([{ text: Translations.settings.breadcrumbText }]);

useUptimeTelemetry(UptimePage.Settings);

Expand All @@ -70,52 +67,32 @@ export const SettingsPage = () => {
dispatch(getDynamicSettings());
}, [dispatch]);

const [formFields, setFormFields] = useState<DynamicSettings | null>(dss.settings || null);

if (!dss.loadError && formFields == null && dss.settings) {
setFormFields({ ...dss.settings });
}
const [formFields, setFormFields] = useState<DynamicSettings>({ ...dss.settings });

const fieldErrors = getFieldErrors(formFields);

const isFormValid = !(fieldErrors && Object.values(fieldErrors).find(v => !!v));

const onChangeFormField: OnFieldChangeType = (field, value) => {
if (formFields) {
const newFormFields = cloneDeep(formFields);
set(newFormFields, field, value);
setFormFields(cloneDeep(newFormFields));
}
};
const onChangeFormField: OnFieldChangeType = changedField =>
setFormFields(Object.assign({ ...merge(formFields, changedField) }));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using merge bcoz Object.assign doesn't take of nested merging, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've gotten rid of merge altogether because it isn't pure and it was editing the state var. I'm wondering if settings shouldn't just be a flat object to avoid recursive concerns when editing slices of it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes i think having a right data structure is important, i do agree, having nested have made a lot of complexity. if you think, it's worth an effort, go ahead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make a follow-up issue.

We have other more important stuff we need to review and it's not worth holding that up for more work in this patch. We don't have any further settings changes planned for the time being, so this complexity shouldn't increase any more than what it is right now until we can get to it. It should be a light patch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


const onApply = (event: React.FormEvent) => {
event.preventDefault();
if (formFields) {
dispatch(setDynamicSettings(formFields));
}
dispatch(setDynamicSettings(formFields));
};

const resetForm = () => {
if (formFields && dss.settings) {
setFormFields({ ...dss.settings });
}
};
const resetForm = () => setFormFields({ ...dss.settings });

const isFormDirty = dss.settings ? !isEqual(dss.settings, formFields) : true;
const isFormDirty = !isEqual(dss.settings, formFields);
const canEdit: boolean =
!!useKibana().services?.application?.capabilities.uptime.configureSettings || false;
const isFormDisabled = dss.loading || !canEdit;

const editNoticeTitle = i18n.translate('xpack.uptime.settings.cannotEditTitle', {
defaultMessage: 'You do not have permission to edit settings.',
});
const editNoticeText = i18n.translate('xpack.uptime.settings.cannotEditText', {
defaultMessage:
"Your user currently has 'Read' permissions for the Uptime app. Enable a permissions-level of 'All' to edit these settings.",
});
const cannotEditNotice = canEdit ? null : (
<>
<EuiCallOut title={editNoticeTitle}>{editNoticeText}</EuiCallOut>
<EuiCallOut title={Translations.settings.editNoticeTitle}>
{Translations.settings.editNoticeText}
</EuiCallOut>
<EuiSpacer size="s" />
</>
);
Expand All @@ -124,9 +101,7 @@ export const SettingsPage = () => {
<>
<Link to={OVERVIEW_ROUTE} data-test-subj="uptimeSettingsToOverviewLink">
<EuiButtonEmpty size="s" color="primary" iconType="arrowLeft">
{i18n.translate('xpack.uptime.settings.returnToOverviewLinkLabel', {
defaultMessage: 'Return to overview',
})}
{Translations.settings.returnToOverviewLinkLabel}
</EuiButtonEmpty>
</Link>
<EuiSpacer size="s" />
Expand Down
23 changes: 23 additions & 0 deletions x-pack/legacy/plugins/uptime/public/pages/translations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 { i18n } from '@kbn/i18n';

export const settings = {
breadcrumbText: i18n.translate('xpack.uptime.settingsBreadcrumbText', {
defaultMessage: 'Settings',
}),
editNoticeTitle: i18n.translate('xpack.uptime.settings.cannotEditTitle', {
defaultMessage: 'You do not have permission to edit settings.',
}),
editNoticeText: i18n.translate('xpack.uptime.settings.cannotEditText', {
defaultMessage:
"Your user currently has 'Read' permissions for the Uptime app. Enable a permissions-level of 'All' to edit these settings.",
}),
returnToOverviewLinkLabel: i18n.translate('xpack.uptime.settings.returnToOverviewLinkLabel', {
defaultMessage: 'Return to overview',
}),
};
Loading