Skip to content

Commit

Permalink
fix: [M3-7521 & M3-7556 & M3-7581] - Update AGLB Service Target Valid…
Browse files Browse the repository at this point in the history
…ation & Fix Route Rules being cleared (#10016)

* update validation

* improve validation

* fix other bug

* Added changeset: AGLB route rules being cleared when updating a route

* Added changeset: AGLB Service Target validation

* add placheolder test

* disable save in edit mode when there is no changes

* fix e2e test by filling out required form

* remove ability to toggle service target health checks

* fix drawer showing as edit mode after deletion

* pass null for path and host in preporation for API change

* allow host to be null for tcp healthchecks

* fix healthcheck protocol toolip icon alignment

* remove `Host` as a rule match type option

---------

Co-authored-by: Banks Nussman <banks@nussman.us>
  • Loading branch information
bnussman-akamai and bnussman authored Jan 5, 2024
1 parent 7f744f9 commit 5cd5707
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 324 deletions.
7 changes: 6 additions & 1 deletion packages/api-v4/src/aglb/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ type Policy =
| 'random'
| 'maglev';

export type MatchField = 'path_prefix' | 'query' | 'host' | 'header' | 'method';
export type MatchField =
| 'always_match'
| 'path_prefix'
| 'query'
| 'header'
| 'method';

export interface RoutePayload {
label: string;
Expand Down
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10016-fixed-1703172060704.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

AGLB route rules being cleared when updating a route ([#10016](https://github.com/linode/manager/pull/10016))
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10016-fixed-1703172108441.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

AGLB Service Target validation ([#10016](https://github.com/linode/manager/pull/10016))
Original file line number Diff line number Diff line change
Expand Up @@ -200,20 +200,10 @@ describe('Akamai Global Load Balancer service targets', () => {
.should('be.visible')
.click();

// Confirm that health check options are hidden when health check is disabled.
cy.findByText('Use Health Checks').should('be.visible').click();

cy.get('[data-qa-healthcheck-options]').should('not.exist');

// Re-enable health check, fill out form.
cy.findByText('Use Health Checks')
cy.findByLabelText('Health Check Host')
.scrollIntoView()
.should('be.visible')
.click();

cy.get('[data-qa-healthcheck-options]')
.scrollIntoView()
.should('be.visible');
.type('example.com');

ui.button
.findByTitle('Create Service Target')
Expand Down Expand Up @@ -382,30 +372,6 @@ describe('Akamai Global Load Balancer service targets', () => {
mockServiceTarget.healthcheck.unhealthy_threshold
);

// Confirm that health check options are hidden when health check is disabled.
cy.findByText('Use Health Checks').should('be.visible').click();

cy.get('[data-qa-healthcheck-options]').should('not.exist');

// Re-enable health check, fill out form.
cy.findByText('Use Health Checks')
.scrollIntoView()
.should('be.visible')
.click();

cy.get('[data-qa-healthcheck-options]')
.scrollIntoView()
.should('be.visible');

// Confirm that health check options are restored to defaults after toggle.
cy.findByLabelText('Interval').should('have.value', 10);

cy.findByLabelText('Timeout').should('have.value', 5000);

cy.findByLabelText('Healthy Threshold').should('have.value', 5);

cy.findByLabelText('Unhealthy Threshold').should('have.value', 5);

//Confirm that health check path and host match service target data.
cy.findByLabelText('Health Check Path', { exact: false }).should(
'have.value',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
import { SelectedIcon } from 'src/components/Autocomplete/Autocomplete.styles';
import { BetaChip } from 'src/components/BetaChip/BetaChip';
import { Box } from 'src/components/Box';
import { Divider } from 'src/components/Divider';
import { FormControlLabel } from 'src/components/FormControlLabel';
import { FormHelperText } from 'src/components/FormHelperText';
Expand All @@ -18,7 +17,6 @@ import { Radio } from 'src/components/Radio/Radio';
import { RadioGroup } from 'src/components/RadioGroup';
import { Stack } from 'src/components/Stack';
import { TextField } from 'src/components/TextField';
import { Toggle } from 'src/components/Toggle/Toggle';
import { TooltipIcon } from 'src/components/TooltipIcon';
import { Typography } from 'src/components/Typography';

Expand Down Expand Up @@ -128,10 +126,11 @@ export const ServiceTargetForm = (props: Props) => {
return (
<form onSubmit={formik.handleSubmit}>
<TextField
errorText={formik.errors.label}
errorText={formik.touched.label ? formik.errors.label : undefined}
label="Service Target Label"
name="label"
noMarginTop={!isEditMode}
onBlur={formik.handleBlur}
onChange={formik.handleChange}
value={formik.values.label}
/>
Expand Down Expand Up @@ -214,131 +213,117 @@ export const ServiceTargetForm = (props: Props) => {
text={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Description}
/>
</Stack>
<FormControlLabel
control={
<Toggle
onChange={(_, checked) =>
formik.setFieldValue('healthcheck.interval', checked ? 10 : 0)
<RadioGroup
onChange={(_, value) =>
formik.setFieldValue('healthcheck.protocol', value)
}
sx={{ marginBottom: '0px !important' }}
value={formik.values.healthcheck.protocol}
>
<FormLabel sx={{ alignItems: 'center', display: 'flex' }}>
Protocol
<TooltipIcon
status="help"
sxTooltipIcon={{ marginLeft: 1.5, padding: 0 }}
text={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Protocol}
/>
</FormLabel>
<FormControlLabel control={<Radio />} label="HTTP" value="http" />
<FormControlLabel control={<Radio />} label="TCP" value="tcp" />
<FormHelperText>{formik.errors.healthcheck?.protocol}</FormHelperText>
</RadioGroup>
<Stack direction="row" spacing={2}>
<TextField
InputProps={{
endAdornment: (
<InputAdornment position="start">seconds</InputAdornment>
),
}}
errorText={formik.errors.healthcheck?.interval}
label="Interval"
labelTooltipText={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Interval}
name="healthcheck.interval"
onChange={formik.handleChange}
type="number"
value={formik.values.healthcheck.interval}
/>
<TextField
InputProps={{
endAdornment: (
<InputAdornment position="start">checks</InputAdornment>
),
}}
errorText={formik.errors.healthcheck?.healthy_threshold}
label="Healthy Threshold"
labelTooltipText={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Healthy}
name="healthcheck.healthy_threshold"
onChange={formik.handleChange}
type="number"
value={formik.values.healthcheck.healthy_threshold}
/>
</Stack>
<Stack direction="row" spacing={2}>
<TextField
InputProps={{
endAdornment: (
<InputAdornment position="start">seconds</InputAdornment>
),
}}
errorText={formik.errors.healthcheck?.timeout}
label="Timeout"
labelTooltipText={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Timeout}
name="healthcheck.timeout"
onChange={formik.handleChange}
type="number"
value={formik.values.healthcheck.timeout}
/>
<TextField
InputProps={{
endAdornment: (
<InputAdornment position="start">checks</InputAdornment>
),
}}
errorText={formik.errors.healthcheck?.unhealthy_threshold}
label="Unhealthy Threshold"
labelTooltipText={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Unhealthy}
name="healthcheck.unhealthy_threshold"
onChange={formik.handleChange}
type="number"
value={formik.values.healthcheck.unhealthy_threshold}
/>
</Stack>
{formik.values.healthcheck.protocol === 'http' && (
<>
<TextField
errorText={
formik.touched.healthcheck?.path
? formik.errors.healthcheck?.path
: undefined
}
checked={formik.values.healthcheck.interval !== 0}
label="Health Check Path"
labelTooltipText={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Path}
name="healthcheck.path"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
optional
placeholder="/"
value={formik.values.healthcheck.path}
/>
}
label="Use Health Checks"
/>
{formik.values.healthcheck.interval !== 0 && (
<Box data-qa-healthcheck-options>
<RadioGroup
onChange={(_, value) =>
formik.setFieldValue('healthcheck.protocol', value)
<TextField
errorText={
formik.touched.healthcheck?.host
? formik.errors.healthcheck?.host
: undefined
}
sx={{ marginBottom: '0px !important' }}
value={formik.values.healthcheck.protocol}
>
<FormLabel>
Protocol
<TooltipIcon
status="help"
sxTooltipIcon={{ marginLeft: 1.5, padding: 0 }}
text={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Protocol}
/>
</FormLabel>
<FormControlLabel control={<Radio />} label="HTTP" value="http" />
<FormControlLabel control={<Radio />} label="TCP" value="tcp" />
<FormHelperText>
{formik.errors.healthcheck?.protocol}
</FormHelperText>
</RadioGroup>
<Stack direction="row" spacing={2}>
<TextField
InputProps={{
endAdornment: (
<InputAdornment position="start">seconds</InputAdornment>
),
}}
labelTooltipText={
SERVICE_TARGET_COPY.Tooltips.Healthcheck.Interval
}
errorText={formik.errors.healthcheck?.interval}
label="Interval"
name="healthcheck.interval"
onChange={formik.handleChange}
type="number"
value={formik.values.healthcheck.interval}
/>
<TextField
InputProps={{
endAdornment: (
<InputAdornment position="start">checks</InputAdornment>
),
}}
labelTooltipText={
SERVICE_TARGET_COPY.Tooltips.Healthcheck.Healthy
}
errorText={formik.errors.healthcheck?.healthy_threshold}
label="Healthy Threshold"
name="healthcheck.healthy_threshold"
onChange={formik.handleChange}
type="number"
value={formik.values.healthcheck.healthy_threshold}
/>
</Stack>
<Stack direction="row" spacing={2}>
<TextField
InputProps={{
endAdornment: (
<InputAdornment position="start">seconds</InputAdornment>
),
}}
labelTooltipText={
SERVICE_TARGET_COPY.Tooltips.Healthcheck.Timeout
}
errorText={formik.errors.healthcheck?.timeout}
label="Timeout"
name="healthcheck.timeout"
onChange={formik.handleChange}
type="number"
value={formik.values.healthcheck.timeout}
/>
<TextField
InputProps={{
endAdornment: (
<InputAdornment position="start">checks</InputAdornment>
),
}}
labelTooltipText={
SERVICE_TARGET_COPY.Tooltips.Healthcheck.Unhealthy
}
errorText={formik.errors.healthcheck?.unhealthy_threshold}
label="Unhealthy Threshold"
name="healthcheck.unhealthy_threshold"
onChange={formik.handleChange}
type="number"
value={formik.values.healthcheck.unhealthy_threshold}
/>
</Stack>
{formik.values.healthcheck.protocol === 'http' && (
<>
<TextField
labelTooltipText={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Path}
errorText={formik.errors.healthcheck?.path}
label="Health Check Path"
name="healthcheck.path"
onChange={formik.handleChange}
optional
value={formik.values.healthcheck.path}
/>
<TextField
labelTooltipText={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Host}
errorText={formik.errors.healthcheck?.host}
label="Health Check Host"
name="healthcheck.host"
onChange={formik.handleChange}
optional
value={formik.values.healthcheck.host}
/>
</>
)}
</Box>
label="Health Check Host"
labelTooltipText={SERVICE_TARGET_COPY.Tooltips.Healthcheck.Host}
name="healthcheck.host"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
placeholder="example.org"
value={formik.values.healthcheck.host}
/>
</>
)}
<ActionsPanel
primaryButtonProps={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ export const LoadBalancerServiceTargets = () => {
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [
selectedServiceTarget,
setSelectedServiceTarget,
] = useState<ServiceTarget>();
selectedServiceTargetId,
setSelectedServiceTargetId,
] = useState<number>();

const pagination = usePagination(1, PREFERENCE_KEY);

Expand All @@ -58,12 +58,12 @@ export const LoadBalancerServiceTargets = () => {

const handleEditServiceTarget = (serviceTarget: ServiceTarget) => {
setIsDrawerOpen(true);
setSelectedServiceTarget(serviceTarget);
setSelectedServiceTargetId(serviceTarget.id);
};

const handleDeleteServiceTarget = (serviceTarget: ServiceTarget) => {
setIsDeleteDialogOpen(true);
setSelectedServiceTarget(serviceTarget);
setSelectedServiceTargetId(serviceTarget.id);
};

// If the user types in a search query, filter results by label.
Expand All @@ -80,6 +80,10 @@ export const LoadBalancerServiceTargets = () => {
filter
);

const selectedServiceTarget = data?.data.find(
(serviceTarget) => serviceTarget.id === selectedServiceTargetId
);

if (isLoading) {
return <CircleProgress />;
}
Expand Down Expand Up @@ -192,7 +196,7 @@ export const LoadBalancerServiceTargets = () => {
<ServiceTargetDrawer
onClose={() => {
setIsDrawerOpen(false);
setSelectedServiceTarget(undefined);
setSelectedServiceTargetId(undefined);
}}
loadbalancerId={Number(loadbalancerId)}
open={isDrawerOpen}
Expand Down
Loading

0 comments on commit 5cd5707

Please sign in to comment.