Skip to content

Commit 959e2c4

Browse files
upcoming: [DI-28227] - Integrating Firewall-nodebalancers to ACLP-Alerting (#13089)
* upcoming: [DI-28227] - Integrating Firewall-nobalancers to ACLP-Alerting * fixing a file naming typo * add changeset * upcoming: [DI-28227] - addressing review comments
1 parent ced04e1 commit 959e2c4

27 files changed

+594
-41
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Upcoming Features
3+
---
4+
5+
Integrate Firewall-nodebalancer support for ACLP-Alerting ([#13089](https://github.com/linode/manager/pull/13089))

packages/manager/src/factories/cloudpulse/alerts.ts

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ export const alertFactory = Factory.Sync.makeFactory<Alert>({
245245
updated_by: 'system',
246246
});
247247

248-
const firewallDimensions: Dimension[] = [
248+
const firewallLinodeDimensions: Dimension[] = [
249249
{ label: 'VPC-Subnet', dimension_label: 'vpc_subnet_id', values: [] },
250250
{
251251
label: 'Interface Type',
@@ -257,29 +257,84 @@ const firewallDimensions: Dimension[] = [
257257
{ label: 'Linode Region', dimension_label: 'region_id', values: [] },
258258
];
259259

260+
const firewallNodebalancerDimensions: Dimension[] = [
261+
{ label: 'Protocol', dimension_label: 'protocol', values: ['TCP', 'UDP'] },
262+
{ label: 'IP Version', dimension_label: 'ip_version', values: ['v4', 'v6'] },
263+
{ label: 'NodeBalancer', dimension_label: 'nodebalancer_id', values: [] },
264+
];
265+
260266
export const firewallMetricDefinitionFactory =
261267
Factory.Sync.makeFactory<MetricDefinition>({
262-
label: 'Firewall Metric',
263-
metric: 'firewall_metric',
264-
unit: 'metric_unit',
268+
label: 'Current connections (Linode)',
269+
metric: 'fw_active_connections',
270+
unit: 'Count',
265271
metric_type: 'gauge',
266-
scrape_interval: '300s',
272+
scrape_interval: '60s',
267273
is_alertable: true,
268-
available_aggregate_functions: ['avg', 'sum', 'max', 'min', 'count'],
269-
dimensions: firewallDimensions,
274+
available_aggregate_functions: ['avg', 'max', 'min'],
275+
dimensions: firewallLinodeDimensions,
270276
});
277+
271278
export const firewallMetricDefinitionsResponse: MetricDefinition[] = [
272279
firewallMetricDefinitionFactory.build({
273-
label: 'Current connections',
280+
label: 'Current connections (Linode)',
274281
metric: 'fw_active_connections',
275-
unit: 'count',
282+
unit: 'Count',
276283
available_aggregate_functions: ['avg', 'max', 'min'],
284+
dimensions: firewallLinodeDimensions,
277285
}),
278286
firewallMetricDefinitionFactory.build({
279-
label: 'Ingress packets accepted',
287+
label: 'Ingress Packets Accepted (Linode)',
280288
metric: 'fw_ingress_packets_accepted',
281-
unit: 'packets_per_second',
289+
unit: 'packets/s',
282290
available_aggregate_functions: ['sum'],
291+
dimensions: firewallLinodeDimensions,
292+
}),
293+
firewallMetricDefinitionFactory.build({
294+
label: 'Available Connections (Linode)',
295+
metric: 'fw_available_connections',
296+
unit: 'Count',
297+
available_aggregate_functions: ['avg', 'max', 'min'],
298+
dimensions: firewallLinodeDimensions,
299+
}),
300+
firewallMetricDefinitionFactory.build({
301+
label: 'Ingress Bytes Accepted (Linode)',
302+
metric: 'fw_ingress_bytes_accepted',
303+
unit: 'Bps',
304+
available_aggregate_functions: ['sum'],
305+
dimensions: firewallLinodeDimensions,
306+
}),
307+
firewallMetricDefinitionFactory.build({
308+
label: 'Ingress Bytes Accepted (Node Balancer)',
309+
metric: 'nb_ingress_bytes_accepted',
310+
unit: 'Bps',
311+
scrape_interval: '300s',
312+
available_aggregate_functions: ['sum'],
313+
dimensions: firewallNodebalancerDimensions,
314+
}),
315+
firewallMetricDefinitionFactory.build({
316+
label: 'Ingress Bytes Dropped (Node Balancer)',
317+
metric: 'nb_ingress_bytes_dropped',
318+
unit: 'Bps',
319+
scrape_interval: '300s',
320+
available_aggregate_functions: ['sum'],
321+
dimensions: firewallNodebalancerDimensions,
322+
}),
323+
firewallMetricDefinitionFactory.build({
324+
label: 'Ingress Packets Accepted (Node Balancer)',
325+
metric: 'nb_ingress_packets_accepted',
326+
unit: 'packets/s',
327+
scrape_interval: '300s',
328+
available_aggregate_functions: ['sum'],
329+
dimensions: firewallNodebalancerDimensions,
330+
}),
331+
firewallMetricDefinitionFactory.build({
332+
label: 'Ingress Packets Dropped (Node Balancer)',
333+
metric: 'nb_ingress_packets_dropped',
334+
unit: 'packets/s',
335+
scrape_interval: '300s',
336+
available_aggregate_functions: ['sum'],
337+
dimensions: firewallNodebalancerDimensions,
283338
}),
284339
];
285340

@@ -579,3 +634,21 @@ export const blockStorageMetricCriteria =
579634
},
580635
],
581636
});
637+
638+
export const firewallNodebalancerMetricCriteria =
639+
Factory.Sync.makeFactory<AlertDefinitionMetricCriteria>({
640+
label: 'Ingress Packets Dropped (Node Balancer)',
641+
metric: 'nb_ingress_packets_dropped',
642+
unit: 'packets/s',
643+
aggregate_function: 'sum',
644+
operator: 'gt',
645+
threshold: 1000,
646+
dimension_filters: [
647+
{
648+
label: 'NodeBalancer',
649+
dimension_label: 'nodebalancer_id',
650+
operator: 'in',
651+
value: '333',
652+
},
653+
],
654+
});

packages/manager/src/features/CloudPulse/Alerts/AlertsDetail/RenderAlertsMetricsAndDimensions.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import {
22
type AlertDefinitionMetricCriteria,
33
type CloudPulseServiceType,
44
} from '@linode/api-v4';
5-
import { useAllLinodesQuery, useAllVPCsQuery } from '@linode/queries';
5+
import {
6+
useAllLinodesQuery,
7+
useAllNodeBalancersQuery,
8+
useAllVPCsQuery,
9+
} from '@linode/queries';
610
import { Divider } from '@linode/ui';
711
import { GridLegacy } from '@mui/material';
812
import React, { useMemo } from 'react';
@@ -17,6 +21,7 @@ import {
1721
import { getVPCSubnets } from '../CreateAlert/Criteria/DimensionFilterValue/utils';
1822
import {
1923
LINODE_DIMENSION_LABEL,
24+
NODEBALANCER_DIMENSION_LABEL,
2025
VPC_SUBNET_DIMENSION_LABEL,
2126
} from './constants';
2227
import { DisplayAlertDetailChips } from './DisplayAlertDetailChips';
@@ -47,9 +52,18 @@ export const RenderAlertMetricsAndDimensions = React.memo(
4752
ruleCriteria,
4853
VPC_SUBNET_DIMENSION_LABEL
4954
);
55+
const isNodebalancersRequired = isCheckRequired(
56+
ruleCriteria,
57+
NODEBALANCER_DIMENSION_LABEL
58+
);
5059
// Initialize the query, but only run when needed
5160
const { data: linodes } = useAllLinodesQuery({}, {}, isLinodeRequired);
5261
const { data: vpcs } = useAllVPCsQuery({ enabled: isVPCRequired });
62+
const { data: nodebalancers } = useAllNodeBalancersQuery(
63+
isNodebalancersRequired,
64+
{},
65+
{}
66+
);
5367

5468
// create a map of id to labels for lookup
5569
const linodeMap = useMemo(
@@ -73,6 +87,17 @@ export const RenderAlertMetricsAndDimensions = React.memo(
7387
}, {});
7488
}, [vpcs]);
7589

90+
const nodebalancersMap = useMemo(() => {
91+
return (
92+
nodebalancers?.reduce<Record<string, string>>((acc, nodebalancer) => {
93+
return {
94+
...acc,
95+
[String(nodebalancer.id)]: nodebalancer.label,
96+
};
97+
}, {}) ?? {}
98+
);
99+
}, [nodebalancers]);
100+
76101
if (!ruleCriteria.rules?.length) {
77102
return <NullComponent />;
78103
}
@@ -125,6 +150,7 @@ export const RenderAlertMetricsAndDimensions = React.memo(
125150
serviceType,
126151
value,
127152
vpcSubnetMap,
153+
nodebalancersMap,
128154
}),
129155
]
130156
)}

packages/manager/src/features/CloudPulse/Alerts/AlertsDetail/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export const transformationAllowedOperators: DimensionFilterOperatorType[] = [
88

99
export const LINODE_DIMENSION_LABEL = 'linode_id';
1010
export const VPC_SUBNET_DIMENSION_LABEL = 'vpc_subnet_id';
11+
export const NODEBALANCER_DIMENSION_LABEL = 'nodebalancer_id';

packages/manager/src/features/CloudPulse/Alerts/AlertsDetail/utils.test.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ describe('getResolvedDimensionValue', () => {
8282
'subnet-1': 'VPC-1_subnet-1',
8383
'subnet-2': 'VPC-1_subnet-2',
8484
};
85-
85+
const nodebalancersMap = {
86+
'33': 'nodebalancer-a',
87+
'44': 'nodebalancer-b',
88+
};
8689
it('should return correct transformed value', () => {
8790
const linodeResult = getResolvedDimensionValue({
8891
dimensionFilterKey: 'linode_id',
@@ -91,6 +94,7 @@ describe('getResolvedDimensionValue', () => {
9194
serviceType: 'firewall',
9295
linodeMap,
9396
vpcSubnetMap,
97+
nodebalancersMap,
9498
});
9599
expect(linodeResult).toBe('linode-a, linode-b');
96100

@@ -101,10 +105,23 @@ describe('getResolvedDimensionValue', () => {
101105
serviceType: 'firewall',
102106
linodeMap,
103107
vpcSubnetMap,
108+
nodebalancersMap,
104109
});
105110
expect(vpcResult).toBe('VPC-1_subnet-1');
106111
});
107112

113+
it('should return correct transformed value for nodebalancer_id', () => {
114+
const nodebalancerResult = getResolvedDimensionValue({
115+
dimensionFilterKey: 'nodebalancer_id',
116+
dimensionOperator: 'in',
117+
value: '33,44',
118+
serviceType: 'firewall',
119+
linodeMap,
120+
vpcSubnetMap,
121+
nodebalancersMap,
122+
});
123+
expect(nodebalancerResult).toBe('nodebalancer-a, nodebalancer-b');
124+
});
108125
it('should not transform value if operator is not in allowed list', () => {
109126
const result = getResolvedDimensionValue({
110127
dimensionFilterKey: 'linode_id',
@@ -113,6 +130,7 @@ describe('getResolvedDimensionValue', () => {
113130
serviceType: 'firewall',
114131
linodeMap,
115132
vpcSubnetMap,
133+
nodebalancersMap,
116134
});
117135
expect(result).toBe('linode-c, linode-d');
118136
});
@@ -125,6 +143,7 @@ describe('getResolvedDimensionValue', () => {
125143
serviceType: 'firewall',
126144
linodeMap,
127145
vpcSubnetMap,
146+
nodebalancersMap,
128147
});
129148
expect(nullResult).toBe('');
130149
});

packages/manager/src/features/CloudPulse/Alerts/AlertsDetail/utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { transformDimensionValue } from '../Utils/utils';
22
import {
33
LINODE_DIMENSION_LABEL,
4+
NODEBALANCER_DIMENSION_LABEL,
45
transformationAllowedOperators,
56
VPC_SUBNET_DIMENSION_LABEL,
67
} from './constants';
@@ -82,6 +83,10 @@ export interface ResolvedDimensionValueProps {
8283
* linode id to label map
8384
*/
8485
linodeMap: Record<string, string>;
86+
/**
87+
* nodebalancer id to label map.
88+
*/
89+
nodebalancersMap: Record<string, string>;
8590
/**
8691
* Service type of the alert.
8792
*/
@@ -108,6 +113,7 @@ export const getResolvedDimensionValue = (
108113
serviceType,
109114
value,
110115
vpcSubnetMap,
116+
nodebalancersMap,
111117
} = props;
112118
if (!value) return '';
113119

@@ -127,6 +133,13 @@ export const getResolvedDimensionValue = (
127133
resolvedValue = resolveIds(value, vpcSubnetMap);
128134
}
129135

136+
if (
137+
dimensionFilterKey === NODEBALANCER_DIMENSION_LABEL &&
138+
transformationAllowedOperators.includes(dimensionOperator)
139+
) {
140+
resolvedValue = resolveIds(value, nodebalancersMap);
141+
}
142+
130143
return transformationAllowedOperators.includes(dimensionOperator)
131144
? transformCommaSeperatedDimensionValues(
132145
resolvedValue,

packages/manager/src/features/CloudPulse/Alerts/AlertsResources/AlertsResources.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import EntityIcon from 'src/assets/icons/entityIcons/alertsresources.svg';
77
import { DebouncedSearchTextField } from 'src/components/DebouncedSearchTextField';
88
import { useResourcesQuery } from 'src/queries/cloudpulse/resources';
99

10+
import { filterFirewallResources } from '../../Utils/utils';
1011
import { StyledPlaceholder } from '../AlertsDetail/AlertDetail';
1112
import { MULTILINE_ERROR_SEPARATOR } from '../constants';
1213
import { AlertListNoticeMessages } from '../Utils/AlertListNoticeMessages';
@@ -41,6 +42,7 @@ import type {
4142
AlertDefinitionType,
4243
CloudPulseServiceType,
4344
Filter,
45+
Firewall,
4446
Region,
4547
} from '@linode/api-v4';
4648

@@ -64,6 +66,11 @@ export interface AlertResourcesProp {
6466
*/
6567
alertType: AlertDefinitionType;
6668

69+
/**
70+
* The entity type for firewall filtering (linode or nodebalancer)
71+
*/
72+
entityType?: 'linode' | 'nodebalancer';
73+
6774
/**
6875
* The error text that needs to displayed incase needed
6976
*/
@@ -106,6 +113,7 @@ export const AlertResources = React.memo((props: AlertResourcesProp) => {
106113
alertLabel,
107114
alertResourceIds = [],
108115
alertType,
116+
entityType,
109117
errorText,
110118
handleResourcesSelection,
111119
hideLabel,
@@ -194,7 +202,12 @@ export const AlertResources = React.memo((props: AlertResourcesProp) => {
194202
), // Enable query only if serviceType and supportedRegionIds are available, in case of firewall only serviceType is needed
195203
serviceType,
196204
{},
197-
xFilterToBeApplied
205+
xFilterToBeApplied,
206+
serviceType === 'firewall' && entityType ? entityType : undefined,
207+
serviceType === 'firewall' && entityType
208+
? (resources: Firewall[]) =>
209+
filterFirewallResources(resources, entityType)
210+
: undefined
198211
);
199212

200213
const regionFilteredResources = React.useMemo(() => {

0 commit comments

Comments
 (0)