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

upcoming: [M3-9088] - Add and update /v4/networking endpoints and types for Linode Interfaces #11559

Merged
merged 11 commits into from
Jan 27, 2025
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Upcoming Features
---

Add and update `/v4/networking` endpoints and types for Linode Interfaces ([#11559](https://github.com/linode/manager/pull/11559))
30 changes: 28 additions & 2 deletions packages/api-v4/src/firewalls/firewalls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ import {
CreateFirewallSchema,
FirewallDeviceSchema,
UpdateFirewallSchema,
UpdateFirewallSettingsSchema,
} from '@linode/validation/lib/firewalls.schema';
import {
CreateFirewallPayload,
Firewall,
FirewallDevice,
FirewallDevicePayload,
FirewallRules,
FirewallSettings,
FirewallTemplate,
FirewallTemplateSlug,
UpdateFirewallPayload,
UpdateFirewallSettings,
} from './types';

/**
Expand Down Expand Up @@ -245,6 +249,29 @@ export const deleteFirewallDevice = (firewallID: number, deviceID: number) =>
)
);

/**
* getFirewallSettings
*
* Returns current interface default firewall settings
*/
export const getFirewallSettings = () =>
Request<FirewallSettings>(
setMethod('GET'),
setURL(`${BETA_API_ROOT}/networking/firewalls/settings`)
);

/**
* getTemplate
*
* Update which firewalls should be the interface default firewalls
*/
export const updateFirewallSettings = (data: UpdateFirewallSettings) =>
Request<FirewallSettings>(
setMethod('PUT'),
setURL(`${BETA_API_ROOT}/networking/firewalls/settings`),
setData(data, UpdateFirewallSettingsSchema)
);

// #region Templates

/**
Expand All @@ -262,9 +289,8 @@ export const getTemplates = () =>
* getTemplate
*
* Get a specific firewall template by its slug.
*
*/
export const getTemplate = (templateSlug: string) =>
export const getTemplate = (templateSlug: FirewallTemplateSlug) =>
Copy link
Contributor Author

@coliu-akamai coliu-akamai Jan 23, 2025

Choose a reason for hiding this comment

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

These two endpoints (getTemplates and getTemplate) were added during the Securing VMs project (see internal ticket - I linked the spec there). I updated the templateSlug type to be more specific - I believe these are the three templates that exist so far, but am not sure. Since there may be a possibility for more slugs I'm not aware of, happy to switch back to string too

I've currently typed it as
export type FirewallTemplateSlug = 'akamai-non-prod' | 'vpc' | 'public'
See internal comments on spec about some naming updates - when testing the endpoint, I saw that vpc and public are the returned slugs

Request<FirewallTemplate>(
setMethod('GET'),
setURL(
Expand Down
31 changes: 23 additions & 8 deletions packages/api-v4/src/firewalls/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export type FirewallStatus = 'enabled' | 'disabled' | 'deleted';

export type FirewallRuleProtocol = 'ALL' | 'TCP' | 'UDP' | 'ICMP' | 'IPENCAP';

export type FirewallDeviceEntityType = 'linode' | 'nodebalancer';
export type FirewallDeviceEntityType = 'linode' | 'nodebalancer' | 'interface';

export type FirewallPolicyType = 'ACCEPT' | 'DROP';

Expand All @@ -14,19 +14,16 @@ export interface Firewall {
rules: FirewallRules;
created: string;
updated: string;
entities: {
id: number;
type: FirewallDeviceEntityType;
label: string;
url: string;
}[];
Comment on lines -17 to -22
Copy link
Contributor Author

@coliu-akamai coliu-akamai Jan 23, 2025

Choose a reason for hiding this comment

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

replacing this with FirewallDeviceEntity since it already exists

export interface FirewallDeviceEntity {
  id: number;
  type: FirewallDeviceEntityType;
  label: string;
  url: string;
}

entities: FirewallDeviceEntity[];
}

export interface FirewallRules {
fingerprint?: string;
coliu-akamai marked this conversation as resolved.
Show resolved Hide resolved
inbound?: FirewallRuleType[] | null;
outbound?: FirewallRuleType[] | null;
inbound_policy: FirewallPolicyType;
outbound_policy: FirewallPolicyType;
version?: number;
}

export interface FirewallRuleType {
Expand Down Expand Up @@ -55,8 +52,10 @@ export interface FirewallDevice {
entity: FirewallDeviceEntity;
}

export type FirewallTemplateSlug = 'akamai-non-prod' | 'vpc' | 'public';

export interface FirewallTemplate {
slug: string;
slug: FirewallTemplateSlug;
rules: FirewallRules;
}

Expand All @@ -67,6 +66,7 @@ export interface CreateFirewallPayload {
devices?: {
linodes?: number[];
nodebalancers?: number[];
interfaces?: number[];
};
}

Expand All @@ -80,3 +80,18 @@ export interface FirewallDevicePayload {
id: number;
type: FirewallDeviceEntityType;
}

export interface DefaultFirewallIDs {
interface_public: number;
interface_vpc: number;
linode: number;
nodebalancer: number;
}

export interface FirewallSettings {
default_firewall_ids: DefaultFirewallIDs;
}

export interface UpdateFirewallSettings {
default_firewall_ids: Partial<DefaultFirewallIDs>;
}
6 changes: 6 additions & 0 deletions packages/api-v4/src/networking/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ export interface IPAddress {
public: boolean;
rdns: string | null;
linode_id: number;
interface_id: number | null;
region: string;
vpc_nat_1_1?: {
address: string;
subnet_id: number;
vpc_id: number;
} | null;
Comment on lines +12 to +16
Copy link
Contributor Author

@coliu-akamai coliu-akamai Jan 23, 2025

Choose a reason for hiding this comment

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

adding this field (looks like we were missing it previously). It got returned either as the object or a null value (or was omitted) when I tested the endpoint

}

export interface IPRangeBaseData {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Fix type errors that result from changes to `/v4/networking` endpoints ([#11559](https://github.com/linode/manager/pull/11559))
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import { firewallQueries } from 'src/queries/firewalls';
import { useCreateFirewall } from 'src/queries/firewalls';

import type { DialogState } from './GenerateFirewallDialog';
import type { CreateFirewallPayload, Firewall } from '@linode/api-v4';
import type {
CreateFirewallPayload,
Firewall,
FirewallTemplateSlug,
} from '@linode/api-v4';
import type { QueryClient } from '@tanstack/react-query';

export const useCreateFirewallFromTemplate = (options: {
onFirewallGenerated?: (firewall: Firewall) => void;
setDialogState: (state: DialogState) => void;
templateSlug: string;
templateSlug: FirewallTemplateSlug;
}) => {
const { onFirewallGenerated, setDialogState, templateSlug } = options;
const queryClient = useQueryClient();
Expand Down Expand Up @@ -44,7 +48,7 @@ export const useCreateFirewallFromTemplate = (options: {
const createFirewallFromTemplate = async (options: {
createFirewall: (firewall: CreateFirewallPayload) => Promise<Firewall>;
queryClient: QueryClient;
templateSlug: string;
templateSlug: FirewallTemplateSlug;
updateProgress: (progress: number | undefined) => void;
}): Promise<Firewall> => {
const { createFirewall, queryClient, templateSlug, updateProgress } = options;
Expand All @@ -66,7 +70,7 @@ const createFirewallFromTemplate = async (options: {
};

const getUniqueFirewallLabel = (
templateSlug: string,
templateSlug: FirewallTemplateSlug,
firewalls: Firewall[]
) => {
let iterator = 1;
Expand All @@ -79,7 +83,10 @@ const getUniqueFirewallLabel = (
return firewallLabelFromSlug(templateSlug, iterator);
};

const firewallLabelFromSlug = (slug: string, iterator: number) => {
const firewallLabelFromSlug = (
slug: FirewallTemplateSlug,
iterator: number
) => {
const MAX_LABEL_LENGTH = 32;
const iteratorSuffix = `-${iterator}`;
return (
Expand Down
14 changes: 13 additions & 1 deletion packages/manager/src/factories/firewalls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
FirewallRuleType,
FirewallRules,
FirewallTemplate,
FirewallTemplateSlug,
} from '@linode/api-v4/lib/firewalls/types';

export const firewallRuleFactory = Factory.Sync.makeFactory<FirewallRuleType>({
Expand Down Expand Up @@ -58,9 +59,20 @@ export const firewallDeviceFactory = Factory.Sync.makeFactory<FirewallDevice>({
updated: '2020-01-01',
});

const firewallTemplateSlugs: FirewallTemplateSlug[] = [
'akamai-non-prod',
'vpc',
'public',
];

export const firewallTemplateFactory = Factory.Sync.makeFactory<FirewallTemplate>(
{
rules: firewallRulesFactory.build(),
slug: Factory.each((i) => `template-${i}`),
slug: Factory.each((_) => {
const randomIndex = Math.floor(
Math.random() * firewallTemplateSlugs.length
);
return firewallTemplateSlugs[randomIndex];
}),
coliu-akamai marked this conversation as resolved.
Show resolved Hide resolved
}
);
3 changes: 3 additions & 0 deletions packages/manager/src/factories/linodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const linodeIPFactory = Factory.Sync.makeFactory<LinodeIPsResponse>({
{
address: '10.11.12.13',
gateway: '10.11.12.13',
interface_id: null,
linode_id: 1,
prefix: 24,
public: true,
Expand All @@ -95,6 +96,7 @@ export const linodeIPFactory = Factory.Sync.makeFactory<LinodeIPsResponse>({
link_local: {
address: '2001:DB8::0000',
gateway: 'fe80::1',
interface_id: null,
linode_id: 1,
prefix: 64,
public: false,
Expand All @@ -106,6 +108,7 @@ export const linodeIPFactory = Factory.Sync.makeFactory<LinodeIPsResponse>({
slaac: {
address: '2001:DB8::0000',
gateway: 'fe80::1',
interface_id: null,
linode_id: 1,
prefix: 64,
public: true,
Expand Down
4 changes: 3 additions & 1 deletion packages/manager/src/factories/networking.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { IPAddress } from '@linode/api-v4/lib/networking';
import Factory from 'src/factories/factoryProxy';

import type { IPAddress } from '@linode/api-v4/lib/networking';

export const ipAddressFactory = Factory.Sync.makeFactory<IPAddress>({
address: Factory.each((id) => `192.168.1.${id}`),
gateway: Factory.each((id) => `192.168.1.${id + 1}`),
interface_id: Factory.each((id) => id),
linode_id: Factory.each((id) => id),
prefix: 24,
public: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const secondaryFirewallEntityNameMap: Record<
FirewallDeviceEntityType,
string
> = {
interface: 'Interface',
linode: 'Linode',
nodebalancer: 'NodeBalancer',
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface FirewallDeviceLandingProps {
}

export const formattedTypes = {
interface: 'Interface', // @Todo Linode Interface: double check this when working on UI tickets
linode: 'Linode',
nodebalancer: 'NodeBalancer',
};
Expand Down
3 changes: 2 additions & 1 deletion packages/manager/src/queries/firewalls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type {
FirewallDevicePayload,
FirewallRules,
FirewallTemplate,
FirewallTemplateSlug,
Params,
ResourcePage,
} from '@linode/api-v4';
Expand Down Expand Up @@ -84,7 +85,7 @@ export const firewallQueries = createQueryKeys('firewalls', {
},
queryKey: null,
},
template: (slug: string) => ({
template: (slug: FirewallTemplateSlug) => ({
queryFn: () => getTemplate(slug),
queryKey: [slug],
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/validation": Upcoming Features
---

Add `UpdateFirewallSettingsSchema`for Linode Interfaces project ([#11559](https://github.com/linode/manager/pull/11559))
9 changes: 9 additions & 0 deletions packages/validation/src/firewalls.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,12 @@ export const FirewallDeviceSchema = object({
.required('Device type is required.'),
id: number().required('ID is required.'),
});

export const UpdateFirewallSettingsSchema = object({
default_firewall_ids: object({
interface_public: number(),
interface_vpc: number(),
linode: number(),
nodebalancer: number(),
}),
});
Loading