Skip to content

Commit 2ee293c

Browse files
authored
tech-story: [M3-9248] - Add MSW crud support for assigning Linodes to a VPC (#12503)
* some types / comments * connect back to VPC when creating Linode Interface * rearrange files for organization * don't save configInterfaces actually - more complicated * fix some id issues * append config interface * i'm thinking...maybe * update subnet/vpc updating logic * update interface deletion * fix some bugs * and a couple more * whack a mole * firewalls * consolidate shared logic * Added changeset: Add MSW crud support for assigning Linodes to a VPC
1 parent 7876d54 commit 2ee293c

9 files changed

Lines changed: 828 additions & 495 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Tech Stories
3+
---
4+
5+
Add MSW crud support for assigning Linodes to a VPC ([#12503](https://github.com/linode/manager/pull/12503))

packages/manager/src/mocks/mockState.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const getStateSeederGroups = (
2323

2424
export const emptyStore: MockState = {
2525
cloudnats: [],
26+
configInterfaces: [],
2627
domainRecords: [],
2728
domains: [],
2829
eventQueue: [],
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import { linodeConfigInterfaceFactory } from '@linode/utilities';
2+
import { http } from 'msw';
3+
4+
import {
5+
makeNotFoundResponse,
6+
makePaginatedResponse,
7+
makeResponse,
8+
} from 'src/mocks/utilities/response';
9+
10+
import { mswDB } from '../../../../indexedDB';
11+
import { addInterfaceToSubnet, removeInterfaceFromSubnet } from './utils';
12+
13+
import type { Config, Interface } from '@linode/api-v4';
14+
import type { StrictResponse } from 'msw';
15+
import type { MockState } from 'src/mocks/types';
16+
import type {
17+
APIErrorResponse,
18+
APIPaginatedResponse,
19+
} from 'src/mocks/utilities/response';
20+
21+
export const getConfigs = () => [
22+
http.get(
23+
'*/v4*/linode/instances/:id/configs',
24+
async ({
25+
params,
26+
request,
27+
}): Promise<
28+
StrictResponse<APIErrorResponse | APIPaginatedResponse<Config>>
29+
> => {
30+
const id = Number(params.id);
31+
const linode = await mswDB.get('linodes', id);
32+
const linodeConfigs = await mswDB.getAll('linodeConfigs');
33+
const configInterfaces = await mswDB.getAll('configInterfaces');
34+
35+
if (!linode || !linodeConfigs || !configInterfaces) {
36+
return makeNotFoundResponse();
37+
}
38+
39+
const configs = linodeConfigs
40+
.filter((configTuple) => configTuple[0] === id)
41+
.map((configTuple) => {
42+
const interfacesForConfig = configInterfaces
43+
.filter((interfaceTuple) => interfaceTuple[0] === configTuple[1].id)
44+
.map((interfaceTuple) => interfaceTuple[1]);
45+
return { ...configTuple[1], interfaces: interfacesForConfig };
46+
});
47+
48+
return makePaginatedResponse({
49+
data: configs,
50+
request,
51+
});
52+
}
53+
),
54+
55+
http.get(
56+
'*/v4*/linode/instances/:id/configs/:configId',
57+
async ({ params }): Promise<StrictResponse<APIErrorResponse | Config>> => {
58+
const id = Number(params.id);
59+
const linode = await mswDB.get('linodes', id);
60+
const configId = Number(params.configId);
61+
const linodeConfig = await mswDB.get('linodeConfigs', configId);
62+
const configInterfaces = await mswDB.getAll('configInterfaces');
63+
64+
if (!linode || !linodeConfig || !configInterfaces) {
65+
return makeNotFoundResponse();
66+
}
67+
68+
const interfaces = configInterfaces
69+
.filter((interfaceTuple) => interfaceTuple[0] === configId)
70+
.map((interfaceTuple) => interfaceTuple[1]);
71+
72+
return makeResponse({
73+
...linodeConfig[1],
74+
interfaces,
75+
});
76+
}
77+
),
78+
];
79+
80+
export const appendConfigInterface = (mockState: MockState) => [
81+
http.post(
82+
'*/v4*/linode/instances/:id/configs/:configId/interfaces',
83+
async ({
84+
params,
85+
request,
86+
}): Promise<StrictResponse<APIErrorResponse | Interface>> => {
87+
const linodeId = Number(params.id);
88+
const linode = await mswDB.get('linodes', linodeId);
89+
const configId = Number(params.configId);
90+
const config = await mswDB.get('linodeConfigs', configId);
91+
92+
if (!linode || !config) {
93+
return makeNotFoundResponse();
94+
}
95+
96+
const interfacePayload = await request.clone().json();
97+
const configInterface = linodeConfigInterfaceFactory.build({
98+
...interfacePayload,
99+
active: true,
100+
});
101+
102+
const newlyAddedConfigInterface = await mswDB.add(
103+
'configInterfaces',
104+
[configId, configInterface],
105+
mockState
106+
);
107+
108+
if (interfacePayload.purpose === 'vpc') {
109+
await addInterfaceToSubnet({
110+
mockState,
111+
interfaceId: newlyAddedConfigInterface[1].id,
112+
isLinodeInterface: false,
113+
linodeId: linode.id,
114+
configId,
115+
vpcId: configInterface.vpc_id,
116+
subnetId: configInterface.subnet_id,
117+
});
118+
}
119+
120+
return makeResponse(newlyAddedConfigInterface[1]);
121+
}
122+
),
123+
];
124+
125+
export const deleteConfigInterface = (mockState: MockState) => [
126+
http.delete(
127+
'*/v4*/linode/instances/:id/configs/:configId/interfaces/:interfaceId',
128+
async ({ params }): Promise<StrictResponse<APIErrorResponse | {}>> => {
129+
const linodeId = Number(params.id);
130+
const configId = Number(params.configId);
131+
const interfaceId = Number(params.interfaceId);
132+
const linode = await mswDB.get('linodes', linodeId);
133+
const config = await mswDB.get('linodeConfigs', configId);
134+
const configInterfaceTuple = await mswDB.get(
135+
'configInterfaces',
136+
interfaceId
137+
);
138+
139+
if (!linode || !config || !configInterfaceTuple) {
140+
return makeNotFoundResponse();
141+
}
142+
143+
// if the config interface is part of a VPC, we must update the VPC as well
144+
const configInterface = configInterfaceTuple[1];
145+
if (configInterface.purpose === 'vpc' && configInterface.subnet_id) {
146+
await removeInterfaceFromSubnet({
147+
mockState,
148+
configId,
149+
interfaceId: configInterface.id,
150+
isLinodeInterface: false,
151+
subnetId: configInterface.subnet_id,
152+
vpcId: configInterface.vpc_id,
153+
});
154+
}
155+
156+
await mswDB.delete('configInterfaces', interfaceId, mockState);
157+
158+
return makeResponse({});
159+
}
160+
),
161+
];

0 commit comments

Comments
 (0)