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

fix: [M3-7824] - ACLB TCP Rule Creation and other fixes #10264

Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Changed
---

Made `match_condition` optional in Rule types to support TCP rules ([#10264](https://github.com/linode/manager/pull/10264))
6 changes: 3 additions & 3 deletions packages/api-v4/src/aclb/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export interface Route {
label: string;
protocol: RouteProtocol;
rules: {
match_condition: MatchCondition;
match_condition?: MatchCondition;
service_targets: {
id: number;
label: string;
Expand All @@ -83,7 +83,7 @@ export interface CreateRoutePayload {
}

export interface Rule {
match_condition: MatchCondition;
match_condition?: MatchCondition;
service_targets: {
id: number;
label: string;
Expand All @@ -92,7 +92,7 @@ export interface Rule {
}

export interface RulePayload {
match_condition: MatchCondition;
match_condition?: MatchCondition;
service_targets: {
id: number;
label: string;
Expand Down
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10264-fixed-1709749998087.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

ACLB TCP rule creation ([#10264](https://github.com/linode/manager/pull/10264))
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ describe('Akamai Cloud Load Balancer routes page', () => {
.should('be.visible')
.within(() => {
cy.findByLabelText('Hostname Match (optional)')
.should('have.value', routes[0].rules[0].match_condition.hostname)
.should('have.value', routes[0].rules[0].match_condition!.hostname)
.clear()
.type('example.com');

Expand All @@ -558,7 +558,7 @@ describe('Akamai Cloud Load Balancer routes page', () => {
cy.findByLabelText('Match Value')
.should(
'have.value',
routes[0].rules[0].match_condition.match_value
routes[0].rules[0].match_condition!.match_value
)
.clear()
.type('x-header=my-header-value');
Expand Down Expand Up @@ -604,7 +604,7 @@ describe('Akamai Cloud Load Balancer routes page', () => {

// Verify all rules are shown
for (const rule of routes[0].rules) {
cy.findByText(rule.match_condition.match_value).should('be.visible');
cy.findByText(rule.match_condition!.match_value).should('be.visible');
}

const indexOfRuleToDelete = 1;
Expand All @@ -625,7 +625,7 @@ describe('Akamai Cloud Load Balancer routes page', () => {

// Verify the deleted rule no longer shows
cy.findByText(
routes[0].rules[indexOfRuleToDelete].match_condition.match_value
routes[0].rules[indexOfRuleToDelete].match_condition!.match_value
).should('not.exist');
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,25 @@ describe('RuleDrawer', () => {

const hostnameField = getByLabelText('Hostname Match (optional)');
expect(hostnameField).toHaveDisplayValue(
props.route.rules[0].match_condition.hostname!
props.route.rules[0].match_condition!.hostname!
);

const matchTypeField = getByLabelText('Match Type');
expect(matchTypeField).toHaveDisplayValue('Path Prefix');

const matchValueField = getByLabelText('Match Value');
expect(matchValueField).toHaveDisplayValue(
props.route.rules[0].match_condition.match_value
props.route.rules[0].match_condition!.match_value
);

const cookieField = getByLabelText('Cookie Key');
expect(cookieField).toHaveDisplayValue(
props.route.rules[0].match_condition.session_stickiness_cookie!
props.route.rules[0].match_condition!.session_stickiness_cookie!
);

const ttlField = getByLabelText('Stickiness TTL');
expect(ttlField).toHaveDisplayValue(
String(props.route.rules[0].match_condition.session_stickiness_ttl)
String(props.route.rules[0].match_condition!.session_stickiness_ttl)
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ import { useLoadBalancerRouteUpdateMutation } from 'src/queries/aclb/routes';
import { getFormikErrorsFromAPIErrors } from 'src/utilities/formikErrorUtils';

import { ServiceTargetSelect } from '../ServiceTargets/ServiceTargetSelect';
import { MatchTypeInfo } from './MatchTypeInfo';
import { ROUTE_COPY } from './constants';
import { MatchTypeInfo } from './MatchTypeInfo';
import {
TimeUnit,
defaultServiceTarget,
defaultTTL,
defaultTTLUnit,
getInitialValues,
getIsSessionStickinessEnabled,
getNormalizedRulePayload,
initialValues,
matchTypeOptions,
matchValuePlaceholder,
stickyOptions,
Expand Down Expand Up @@ -77,6 +77,8 @@ export const RuleDrawer = (props: Props) => {

const [ttlUnit, setTTLUnit] = useState<TimeUnit>(defaultTTLUnit);

const initialValues = getInitialValues(protocol);

const formik = useFormik<RulePayload>({
enableReinitialize: true,
initialValues: isEditMode
Expand Down Expand Up @@ -155,7 +157,7 @@ export const RuleDrawer = (props: Props) => {
const isStickinessEnabled = getIsSessionStickinessEnabled(formik.values);

const cookieType =
formik.values.match_condition.session_stickiness_ttl === null
formik.values.match_condition?.session_stickiness_ttl === null
? stickyOptions[1]
: stickyOptions[0];

Expand Down Expand Up @@ -219,27 +221,22 @@ export const RuleDrawer = (props: Props) => {
{route?.protocol !== 'tcp' && (
<>
<TextField
errorText={
formik.touched.match_condition?.hostname
? formik.errors.match_condition?.hostname
: undefined
}
errorText={getIn(formik.errors, 'match_condition.hostname')}
label="Hostname Match"
labelTooltipText={ROUTE_COPY.Rule.Hostname}
name="match_condition.hostname"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
optional
placeholder="www.example.org"
value={formik.values.match_condition.hostname}
value={formik.values.match_condition?.hostname}
/>
<Stack direction="row" spacing={2}>
<Autocomplete
errorText={
formik.touched.match_condition?.match_field
? formik.errors.match_condition?.match_field
: undefined
}
errorText={getIn(
formik.errors,
'match_condition.match_field'
)}
onBlur={() =>
formik.setFieldTouched('match_condition.match_field')
}
Expand All @@ -253,7 +250,7 @@ export const RuleDrawer = (props: Props) => {
matchTypeOptions.find(
(option) =>
option.value ===
formik.values.match_condition.match_field
formik.values.match_condition?.match_field
) ?? matchTypeOptions[0]
}
disableClearable
Expand All @@ -264,26 +261,28 @@ export const RuleDrawer = (props: Props) => {
/>
<TextField
errorText={
formik.touched.match_condition?.match_value
? formik.errors.match_condition?.match_value
getIn(formik.touched, 'match_condition.match_value')
? getIn(formik.errors, 'match_condition.match_value')
: undefined
}
labelTooltipText={
ROUTE_COPY.Rule.MatchValue[
formik.values.match_condition.match_field
formik.values.match_condition?.match_field ??
'always_match'
]
}
placeholder={
matchValuePlaceholder[
formik.values.match_condition.match_field
formik.values.match_condition?.match_field ??
'always_match'
]
}
containerProps={{ sx: { flexGrow: 1 } }}
label="Match Value"
name="match_condition.match_value"
onBlur={formik.handleBlur}
onChange={formik.handleChange}
value={formik.values.match_condition.match_value}
value={formik.values.match_condition?.match_value}
/>
</Stack>
<Stack alignItems="center" direction="row" gap={2}>
Expand Down Expand Up @@ -419,14 +418,19 @@ export const RuleDrawer = (props: Props) => {
/>
<TextField
errorText={
formik.touched.match_condition?.session_stickiness_cookie
? formik.errors.match_condition
?.session_stickiness_cookie
getIn(
formik.touched,
'match_condition.session_stickiness_cookie'
)
? getIn(
formik.errors,
'match_condition.session_stickiness_cookie'
)
: undefined
}
value={
formik.values.match_condition.session_stickiness_cookie ??
''
formik.values.match_condition
?.session_stickiness_cookie ?? ''
}
label="Cookie Key"
labelTooltipText={ROUTE_COPY.Rule.Stickiness.Cookie}
Expand All @@ -439,9 +443,14 @@ export const RuleDrawer = (props: Props) => {
<Stack direction="row" spacing={1}>
<TextField
errorText={
formik.touched.match_condition?.session_stickiness_ttl
? formik.errors.match_condition
?.session_stickiness_ttl
getIn(
formik.touched,
'match_condition.session_stickiness_ttl'
)
? getIn(
formik.errors,
'match_condition.session_stickiness_ttl'
)
: undefined
}
onChange={(e) =>
Expand All @@ -453,7 +462,7 @@ export const RuleDrawer = (props: Props) => {
}
value={
(formik.values.match_condition
.session_stickiness_ttl ?? 0) /
?.session_stickiness_ttl ?? 0) /
timeUnitFactorMap[ttlUnit]
}
label="Stickiness TTL"
Expand All @@ -471,11 +480,12 @@ export const RuleDrawer = (props: Props) => {
setTTLUnit(option.key);

if (
formik.values.match_condition.session_stickiness_ttl
formik.values.match_condition
?.session_stickiness_ttl
) {
const oldValue =
formik.values.match_condition
.session_stickiness_ttl;
?.session_stickiness_ttl;

formik.setFieldValue(
'match_condition.session_stickiness_ttl',
Expand All @@ -489,7 +499,7 @@ export const RuleDrawer = (props: Props) => {
disableClearable
label="test"
options={timeUnitOptions}
sx={{ marginTop: '45px !important', minWidth: '140px' }}
sx={{ marginTop: '52px !important', minWidth: '140px' }}
textFieldProps={{ hideLabel: true }}
/>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,28 @@ export const defaultServiceTarget = {

export const defaultTTLUnit = 'second';

export const initialValues = {
match_condition: {
hostname: '',
match_field: 'path_prefix' as const,
match_value: '',
session_stickiness_cookie: null,
session_stickiness_ttl: null,
},
service_targets: [defaultServiceTarget],
export const getInitialValues = (protocol: Route['protocol']) => {
if (protocol === 'tcp') {
return { service_targets: [defaultServiceTarget] };
}
return {
match_condition: {
hostname: '',
match_field: 'path_prefix' as const,
match_value: '',
session_stickiness_cookie: null,
session_stickiness_ttl: null,
},
service_targets: [defaultServiceTarget],
};
};

export const getIsSessionStickinessEnabled = (
rule: Rule | RulePayload | RuleCreatePayload
) => {
return (
rule.match_condition.session_stickiness_cookie !== null ||
rule.match_condition.session_stickiness_ttl !== null
rule.match_condition?.session_stickiness_cookie !== null ||
rule.match_condition?.session_stickiness_ttl !== null
);
};

Expand All @@ -76,12 +81,14 @@ export const getIsSessionStickinessEnabled = (
* so that the API accepts the payload.
*/
export const getNormalizedRulePayload = (rule: RulePayload) => ({
match_condition: {
...rule.match_condition,
hostname: rule.match_condition.hostname
? rule.match_condition.hostname
: null,
},
match_condition: rule.match_condition
? {
...rule.match_condition,
hostname: rule.match_condition.hostname
? rule.match_condition.hostname
: null,
}
: undefined,
service_targets: rule.service_targets,
});

Expand Down
Loading
Loading