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

change default snr template to be determined according to label #42

Merged
merged 1 commit into from
Dec 27, 2023
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
28 changes: 20 additions & 8 deletions src/apis/useSNRTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
} from "data/types";
import * as React from "react";

const DEFAULT_TEMPLATE_LABEL = "remediation.medik8s.io/default-template";

const useSnrTemplate = (): SnrTemplateResult => {
const [templates, loaded, error] = useK8sWatchResource<
SelfNodeRemediationTemplate[]
Expand All @@ -18,19 +20,29 @@ const useSnrTemplate = (): SnrTemplateResult => {
if (error) {
return undefined;
}
const templateCR = templates.find(

let defaultTemplate = templates.find(
(template) =>
template.spec?.template?.spec?.remediationStrategy ===
"ResourceDeletion"
template.metadata?.labels?.[DEFAULT_TEMPLATE_LABEL] === "true"
);
if (!templateCR) {

if (!defaultTemplate) {
// fallback to resource deletion for backward compatibility of versions without label
defaultTemplate = templates.find(
(template) =>
template.spec?.template?.spec?.remediationStrategy ===
"ResourceDeletion"
);
}

if (!defaultTemplate) {
return undefined;
}
return {
apiVersion: templateCR.apiVersion,
kind: templateCR.kind,
namespace: templateCR.metadata?.namespace,
name: templateCR.metadata?.name,
apiVersion: defaultTemplate.apiVersion,
kind: defaultTemplate.kind,
namespace: defaultTemplate.metadata?.namespace,
name: defaultTemplate.metadata?.name,
};
}, [templates, error]);

Expand Down
55 changes: 39 additions & 16 deletions src/components/editor/NodeHealthCheckForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,28 @@ import { getFormValues, getNodeHealthCheck } from "data/formValues";
import { LoadingInline } from "copiedFromConsole/utils/status-box";
import "./nhc-form.css";
import { useOpenShiftVersion } from "copiedFromConsole/hooks/useOpenShiftVersion";
import useSnrTemplate from "../../apis/useSNRTemplate";
import { range } from "lodash-es";
import { Skeleton } from "@patternfly/react-core";
export interface NodeHealthCheckProps {
title: string;
name: string;
nodeHealthCheck: NodeHealthCheck;
isCreateFlow: boolean;
}

const FormLoading = () => (
<>
<br />
{range(0, 20).map((idx) => (
<>
<Skeleton key={idx} width="50%" />
<br />
</>
))}
</>
);

const LearnMoreLink: React.FC = () => {
const { t } = useNodeHealthCheckTranslation();
const [version, loaded, error] = useOpenShiftVersion();
Expand Down Expand Up @@ -68,10 +83,13 @@ const NodeHealthCheckForm__: React.FC<NodeHealthCheckProps> = ({
isCreateFlow,
}) => {
const { t } = useNodeHealthCheckTranslation();
const initialValues = React.useMemo(
() => getFormValues(nodeHealthCheck, isCreateFlow),
[]
);
const [snrTemplate, loaded] = useSnrTemplate();
const initialValues = React.useMemo(() => {
if (!loaded) {
return undefined;
}
return getFormValues(nodeHealthCheck, isCreateFlow, snrTemplate);
}, [isCreateFlow, loaded, nodeHealthCheck, snrTemplate]);

const navigation = useNodeHealthCheckNavigation();

Expand Down Expand Up @@ -109,18 +127,23 @@ const NodeHealthCheckForm__: React.FC<NodeHealthCheckProps> = ({
return (
<>
<PageHeading title={title} helpText={<HelpText />} />
<Formik
enableReinitialize
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={getValidationSchema(t)}
validateOnMount={true}
>
<NodeHealthCheckSyncedEditor
originalNodeHealthCheck={nodeHealthCheck}
handleCancel={() => navigation.goBack()}
/>
</Formik>
{!loaded ? (
<FormLoading />
) : (
<Formik
enableReinitialize
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={getValidationSchema(t)}
validateOnMount={true}
>
<NodeHealthCheckSyncedEditor
originalNodeHealthCheck={nodeHealthCheck}
handleCancel={() => navigation.goBack()}
snrTemplate={snrTemplate}
/>
</Formik>
)}
</>
);
};
Expand Down
27 changes: 22 additions & 5 deletions src/components/editor/NodeHealthCheckSyncedEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import * as React from "react";

import { useFormikContext } from "formik";
import { useNodeHealthCheckTranslation } from "localization/useNodeHealthCheckTranslation";
import { NodeHealthCheck, NodeHealthCheckFormValues } from "../../data/types";
import {
NodeHealthCheck,
NodeHealthCheckFormValues,
RemediationTemplate,
} from "../../data/types";
import { EditorType } from "../../copiedFromConsole/synced-editor/editor-toggle";
import {
FlexForm,
Expand All @@ -18,6 +22,7 @@ import { dump } from "js-yaml";
import { Alert, FormSection } from "@patternfly/react-core";
import { getFormValues } from "data/formValues";
import { isEmpty } from "lodash-es";

const sanitizeToYaml = (
values: NodeHealthCheckFormValues,
originalNodeHealthCheck: NodeHealthCheck
Expand All @@ -40,11 +45,12 @@ const LAST_VIEWED_EDITOR_TYPE_USERSETTING_KEY =
type NodeHealthCheckFormSyncedEditorProps = {
handleCancel: () => void;
originalNodeHealthCheck: NodeHealthCheck;
snrTemplate: RemediationTemplate;
};

export const NodeHealthCheckSyncedEditor: React.FC<
NodeHealthCheckFormSyncedEditorProps
> = ({ originalNodeHealthCheck, handleCancel }) => {
> = ({ originalNodeHealthCheck, handleCancel, snrTemplate }) => {
const {
values,
status,
Expand Down Expand Up @@ -96,7 +102,11 @@ export const NodeHealthCheckSyncedEditor: React.FC<

const onReload = () => {
const curEditorType = values.editorType;
const resetValues = getFormValues(originalNodeHealthCheck, false);
const resetValues = getFormValues(
originalNodeHealthCheck,
false,
snrTemplate
);
resetValues.editorType = curEditorType;
resetValues.reloadCount++;
resetForm({ values: resetValues });
Expand All @@ -105,6 +115,7 @@ export const NodeHealthCheckSyncedEditor: React.FC<
React.useEffect(() => {
setStatus({ submitError: null });
}, [setStatus, values.editorType]);

return (
<>
<FlexForm className="nhc-form">
Expand All @@ -115,11 +126,17 @@ export const NodeHealthCheckSyncedEditor: React.FC<
editor: formEditor,
sanitizeTo: (yamlNodeHealthCheck: NodeHealthCheck) => {
try {
return formViewValues.getFormViewValues(yamlNodeHealthCheck);
return formViewValues.getFormViewValues(
yamlNodeHealthCheck,
snrTemplate
);
} catch (err) {
//return a function so SyncedEditorField will handle the error properly
return () =>
formViewValues.getFormViewValues(originalNodeHealthCheck);
formViewValues.getFormViewValues(
originalNodeHealthCheck,
snrTemplate
);
}
},
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,6 @@ import {
RemediationTemplate,
} from "../../../../data/types";
import { useNodeHealthCheckTranslation } from "../../../../localization/useNodeHealthCheckTranslation";
import HelpIcon from "../../../shared/HelpIcon";

const SNRRadioButtonLabel: React.FC = () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

remove the help icon since the strategy can change and anyhow the fields are displayed

const { t } = useNodeHealthCheckTranslation();
return (
<>
{getSNRLabel(t)}
<HelpIcon
helpText={t(
"Self node remediation template uses the remediation strategy 'Resource Deletion'."
)}
/>
</>
);
};

const RemediatorKindRadioGroup: React.FC<{
snrTemplatesExist: boolean;
Expand All @@ -50,7 +35,7 @@ const RemediatorKindRadioGroup: React.FC<{
>
<RadioButtonField
value={RemediatorRadioOption.SNR}
label={<SNRRadioButtonLabel />}
label={getSNRLabel(t)}
isDisabled={!snrTemplatesExist}
aria-describedby={"SNR remediator kind"}
name={fieldName}
Expand Down
6 changes: 4 additions & 2 deletions src/data/formValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
FormViewValues,
NodeHealthCheck,
NodeHealthCheckFormValues,
RemediationTemplate,
} from "./types";
import { dump } from "js-yaml";
import { isParseError } from "./parseErrors";
Expand All @@ -13,7 +14,8 @@ import * as yamlText from "./yamlText";

export const getFormValues = (
nodeHealthCheck: NodeHealthCheck,
isCreateFlow: boolean
isCreateFlow: boolean,
snrTemplate: RemediationTemplate | undefined
): NodeHealthCheckFormValues => {
const yamlData = dump(nodeHealthCheck, {
skipInvalid: true,
Expand All @@ -22,7 +24,7 @@ export const getFormValues = (
let formData: FormViewValues | null = null;
let editorType = EditorType.YAML;
try {
formData = getFormViewValues(nodeHealthCheck);
formData = getFormViewValues(nodeHealthCheck, snrTemplate);
editorType = EditorType.Form;
} catch (err) {
if (isParseError(err)) {
Expand Down
21 changes: 13 additions & 8 deletions src/data/formViewValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
selectorToStringArray,
} from "copiedFromConsole/module/selector";
import { defaultUnhealthyConditions, DEFAULT_MIN_HEALTHY } from "./defaults";
import { snrTemplateKind } from "./model";
import { ParseErrorCode, throwParseError } from "./parseErrors";
import { getSortedRemediators } from "./remediator";
import {
Expand All @@ -17,19 +16,20 @@ import {
EscalatingRemediator,
} from "./types";
import { MIN_HEALTHY_REGEX } from "./validationSchema";
import { isEqual } from "lodash-es";

const getRemediationTemplateFormValues = (
snrTemplate: RemediationTemplate | undefined,
template?: RemediationTemplate,
timeout?: string,
order?: number
): Remediator | undefined => {
if (!template) {
return undefined;
}
const radioOption =
template.kind === snrTemplateKind.kind
? RemediatorRadioOption.SNR
: RemediatorRadioOption.CUSTOM;
const radioOption = isEqual(snrTemplate, template)
? RemediatorRadioOption.SNR
: RemediatorRadioOption.CUSTOM;
return {
radioOption,
template,
Expand Down Expand Up @@ -58,14 +58,16 @@ const getUnhealthyConditionsValue = (
};

const getescalatingRemediationsFormValues = (
escalatingRemediations?: EscalatingRemediator[]
escalatingRemediations?: EscalatingRemediator[],
snrTemplate?: RemediationTemplate
): Remediator[] => {
if (!escalatingRemediations) return [];
const sortedescalatingRemediations = getSortedRemediators(
escalatingRemediations
);
return sortedescalatingRemediations.map((remediator) => {
return getRemediationTemplateFormValues(
snrTemplate,
remediator.remediationTemplate,
remediator.timeout,
remediator.order
Expand All @@ -74,7 +76,8 @@ const getescalatingRemediationsFormValues = (
};

export const getFormViewValues = (
nodeHealthCheck: NodeHealthCheck
nodeHealthCheck: NodeHealthCheck,
snrTemplate: RemediationTemplate | undefined
): FormViewValues => {
const useEscalating = !!nodeHealthCheck.spec?.escalatingRemediations;
return {
Expand All @@ -86,11 +89,13 @@ export const getFormViewValues = (
unhealthyConditions: getUnhealthyConditionsValue(nodeHealthCheck),
remediator: !useEscalating
? getRemediationTemplateFormValues(
snrTemplate,
nodeHealthCheck?.spec?.remediationTemplate
)
: undefined,
escalatingRemediations: getescalatingRemediationsFormValues(
nodeHealthCheck.spec?.escalatingRemediations
nodeHealthCheck.spec?.escalatingRemediations,
snrTemplate
),
useEscalating: !!nodeHealthCheck.spec?.escalatingRemediations,
};
Expand Down