Skip to content

Commit 3301772

Browse files
committed
fix(ec2): discover and add more EC2 errors
1 parent aa27035 commit 3301772

File tree

3 files changed

+342
-40
lines changed

3 files changed

+342
-40
lines changed

scripts/discover-ec2-errors.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* Discover EC2 API error codes by making calls with invalid IDs.
3+
* Usage: bun run scripts/discover-ec2-errors.ts
4+
*/
5+
import { fromNodeProviderChain } from "@aws-sdk/credential-providers";
6+
import { Effect } from "effect";
7+
import { EC2 } from "../src/services/ec2/index.ts";
8+
import { servicePatches } from "./service-patches.ts";
9+
10+
const credentials = await fromNodeProviderChain()();
11+
const client = new EC2({ region: "us-east-1", credentials });
12+
13+
// Fake IDs using valid format (17 hex chars after prefix for most)
14+
const opParams: Record<string, Record<string, unknown>> = {
15+
// VPC resources (17 hex chars)
16+
DeleteVpc: { VpcId: "vpc-0a1b2c3d4e5f67890" },
17+
DescribeVpcs: { VpcIds: ["vpc-0a1b2c3d4e5f67890"] },
18+
DeleteSubnet: { SubnetId: "subnet-0a1b2c3d4e5f67890" },
19+
DescribeSubnets: { SubnetIds: ["subnet-0a1b2c3d4e5f67890"] },
20+
DeleteInternetGateway: { InternetGatewayId: "igw-0a1b2c3d4e5f67890" },
21+
DescribeInternetGateways: { InternetGatewayIds: ["igw-0a1b2c3d4e5f67890"] },
22+
DeleteNatGateway: { NatGatewayId: "nat-0a1b2c3d4e5f67890" },
23+
DescribeNatGateways: { NatGatewayIds: ["nat-0a1b2c3d4e5f67890"] },
24+
DeleteRouteTable: { RouteTableId: "rtb-0a1b2c3d4e5f67890" },
25+
DescribeRouteTables: { RouteTableIds: ["rtb-0a1b2c3d4e5f67890"] },
26+
DeleteNetworkAcl: { NetworkAclId: "acl-0a1b2c3d4e5f67890" },
27+
DescribeNetworkAcls: { NetworkAclIds: ["acl-0a1b2c3d4e5f67890"] },
28+
DeleteSecurityGroup: { GroupId: "sg-0a1b2c3d4e5f67890" },
29+
DescribeSecurityGroups: { GroupIds: ["sg-0a1b2c3d4e5f67890"] },
30+
DeleteNetworkInterface: { NetworkInterfaceId: "eni-0a1b2c3d4e5f67890" },
31+
DescribeNetworkInterfaces: { NetworkInterfaceIds: ["eni-0a1b2c3d4e5f67890"] },
32+
// Instance/AMI
33+
DescribeInstances: { InstanceIds: ["i-0a1b2c3d4e5f67890"] },
34+
DescribeImages: { ImageIds: ["ami-0a1b2c3d4e5f67890"] },
35+
// Volume/Snapshot
36+
DeleteVolume: { VolumeId: "vol-0a1b2c3d4e5f67890" },
37+
DescribeVolumes: { VolumeIds: ["vol-0a1b2c3d4e5f67890"] },
38+
DeleteSnapshot: { SnapshotId: "snap-0a1b2c3d4e5f67890" },
39+
DescribeSnapshots: { SnapshotIds: ["snap-0a1b2c3d4e5f67890"] },
40+
// Gateway resources
41+
DeleteCustomerGateway: { CustomerGatewayId: "cgw-0a1b2c3d4e5f67890" },
42+
DescribeCustomerGateways: { CustomerGatewayIds: ["cgw-0a1b2c3d4e5f67890"] },
43+
DeleteVpnGateway: { VpnGatewayId: "vgw-0a1b2c3d4e5f67890" },
44+
DescribeVpnGateways: { VpnGatewayIds: ["vgw-0a1b2c3d4e5f67890"] },
45+
DeleteVpnConnection: { VpnConnectionId: "vpn-0a1b2c3d4e5f67890" },
46+
DescribeVpnConnections: { VpnConnectionIds: ["vpn-0a1b2c3d4e5f67890"] },
47+
// DHCP
48+
DeleteDhcpOptions: { DhcpOptionsId: "dopt-0a1b2c3d4e5f67890" },
49+
DescribeDhcpOptions: { DhcpOptionsIds: ["dopt-0a1b2c3d4e5f67890"] },
50+
// Keys
51+
DeleteKeyPair: { KeyName: "nonexistent-key-12345" },
52+
DescribeKeyPairs: { KeyNames: ["nonexistent-key-12345"] },
53+
// Addresses
54+
DescribeAddresses: { AllocationIds: ["eipalloc-0a1b2c3d4e5f6789"] },
55+
// Egress-only IGW
56+
DeleteEgressOnlyInternetGateway: {
57+
EgressOnlyInternetGatewayId: "eigw-0a1b2c3d4e5f67890",
58+
},
59+
DescribeEgressOnlyInternetGateways: {
60+
EgressOnlyInternetGatewayIds: ["eigw-0a1b2c3d4e5f67890"],
61+
},
62+
};
63+
64+
async function testOp(opName: string) {
65+
const params = opParams[opName];
66+
if (!params) return { op: opName, error: null, skip: "no params" };
67+
68+
const methodName = opName.charAt(0).toLowerCase() + opName.slice(1);
69+
const method = (client as any)[methodName];
70+
if (!method) return { op: opName, error: null, skip: "no method" };
71+
72+
try {
73+
await Effect.runPromise(method.call(client, params));
74+
return { op: opName, error: null, skip: "no error" };
75+
} catch (e: any) {
76+
// Extract error code from various possible locations
77+
let code = e?._tag || e?.name || e?.Code || e?.code;
78+
// Handle Effect's FiberFailure wrapper - look for the actual error inside
79+
if (e?.toString) {
80+
const str = e.toString();
81+
// Extract error code pattern like "InvalidVpcID.NotFound" or "NatGatewayMalformed"
82+
const match = str.match(
83+
/Invalid[\w.]+|[\w]+NotFound|[\w]+Malformed|[\w]+LimitExceeded|DependencyViolation|InsufficientInstanceCapacity/,
84+
);
85+
if (match) code = match[0];
86+
}
87+
return { op: opName, error: code || "Unknown" };
88+
}
89+
}
90+
91+
const ops = Object.keys(servicePatches.ec2).filter(
92+
(op) => op.startsWith("Delete") || op.startsWith("Describe"),
93+
);
94+
95+
console.log(`Testing ${ops.length} operations...\n`);
96+
97+
for (const op of ops) {
98+
const { error, skip } = await testOp(op);
99+
const expected = servicePatches.ec2[op]?.errors ?? [];
100+
const match = error ? expected.includes(error) : false;
101+
const icon = skip ? "⏭️" : match ? "✅" : "⚠️";
102+
console.log(
103+
`${icon} ${op}: ${error ?? skip} (expected: ${expected.join(", ") || "none"})`,
104+
);
105+
}

scripts/service-patches.ts

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ export const servicePatches: Record<string, ServicePatches> = {
203203
},
204204

205205
// ========== Customer Gateway Operations ==========
206+
CreateCustomerGateway: {
207+
errors: [
208+
"InvalidCustomerGateway.DuplicateIpAddress",
209+
"CustomerGatewayLimitExceeded",
210+
],
211+
},
206212
DeleteCustomerGateway: {
207213
errors: ["InvalidCustomerGatewayID.NotFound"],
208214
},
@@ -214,6 +220,9 @@ export const servicePatches: Record<string, ServicePatches> = {
214220
},
215221

216222
// ========== DHCP Options Operations ==========
223+
CreateDhcpOptions: {
224+
errors: ["DhcpOptionsLimitExceeded"],
225+
},
217226
AssociateDhcpOptions: {
218227
errors: ["InvalidDhcpOptionID.NotFound", "InvalidVpcID.NotFound"],
219228
},
@@ -340,7 +349,7 @@ export const servicePatches: Record<string, ServicePatches> = {
340349
],
341350
},
342351
ModifyInstanceCreditSpecification: {
343-
errors: ["InvalidInstanceID.NotFound"],
352+
errors: ["InstanceCreditSpecification.NotSupported"],
344353
},
345354
ModifyInstanceEventStartTime: {
346355
errors: ["InvalidInstanceID.NotFound"],
@@ -384,6 +393,20 @@ export const servicePatches: Record<string, ServicePatches> = {
384393
UnmonitorInstances: {
385394
errors: ["InvalidInstanceID.NotFound"],
386395
},
396+
RunInstances: {
397+
errors: [
398+
"InvalidAMIID.NotFound",
399+
"InvalidAMIID.Malformed",
400+
"InvalidAMIID.Unavailable",
401+
"InvalidSubnetID.NotFound",
402+
"InvalidSecurityGroupId.NotFound",
403+
"InvalidKeyPair.NotFound",
404+
"InvalidBlockDeviceMapping",
405+
"InvalidInstanceType",
406+
"InvalidParameterValue",
407+
"InsufficientInstanceCapacity",
408+
],
409+
},
387410

388411
// ========== Instance Event Window Operations ==========
389412
AssociateInstanceEventWindow: {
@@ -401,16 +424,33 @@ export const servicePatches: Record<string, ServicePatches> = {
401424

402425
// ========== Internet Gateway Operations ==========
403426
AttachInternetGateway: {
404-
errors: ["InvalidInternetGatewayID.NotFound", "InvalidVpcID.NotFound"],
427+
errors: [
428+
"InvalidInternetGatewayID.NotFound",
429+
"InvalidInternetGatewayId.Malformed",
430+
"InvalidVpcID.NotFound",
431+
"Resource.AlreadyAssociated",
432+
],
405433
},
406434
DeleteInternetGateway: {
407-
errors: ["InvalidInternetGatewayID.NotFound"],
435+
errors: [
436+
"InvalidInternetGatewayID.NotFound",
437+
"InvalidInternetGatewayId.Malformed",
438+
"DependencyViolation",
439+
],
408440
},
409441
DescribeInternetGateways: {
410-
errors: ["InvalidInternetGatewayID.NotFound"],
442+
errors: [
443+
"InvalidInternetGatewayID.NotFound",
444+
"InvalidInternetGatewayId.Malformed",
445+
],
411446
},
412447
DetachInternetGateway: {
413-
errors: ["InvalidInternetGatewayID.NotFound", "InvalidVpcID.NotFound"],
448+
errors: [
449+
"InvalidInternetGatewayID.NotFound",
450+
"InvalidInternetGatewayId.Malformed",
451+
"InvalidVpcID.NotFound",
452+
"Gateway.NotAttached",
453+
],
414454
},
415455

416456
// ========== Key Pair Operations ==========
@@ -522,18 +562,22 @@ export const servicePatches: Record<string, ServicePatches> = {
522562
],
523563
},
524564
DeleteNatGateway: {
525-
errors: ["InvalidNatGatewayID.NotFound"],
565+
errors: ["NatGatewayNotFound", "NatGatewayMalformed"],
526566
},
527567
DescribeNatGateways: {
528-
errors: ["InvalidNatGatewayID.NotFound"],
568+
errors: ["NatGatewayNotFound", "NatGatewayMalformed"],
529569
},
530570

531571
// ========== Network ACL Operations ==========
532572
CreateNetworkAclEntry: {
533573
errors: ["InvalidNetworkAclID.NotFound"],
534574
},
535575
DeleteNetworkAcl: {
536-
errors: ["InvalidNetworkAclID.NotFound", "InvalidNetworkAcl.InUse"],
576+
errors: [
577+
"InvalidNetworkAclID.NotFound",
578+
"InvalidNetworkAclId.Malformed",
579+
"InvalidNetworkAcl.InUse",
580+
],
537581
},
538582
DeleteNetworkAclEntry: {
539583
errors: [
@@ -754,6 +798,7 @@ export const servicePatches: Record<string, ServicePatches> = {
754798
errors: [
755799
"InvalidGroup.NotFound",
756800
"InvalidSecurityGroupId.NotFound",
801+
"InvalidGroupId.Malformed",
757802
"InvalidGroup.InUse",
758803
],
759804
},
@@ -805,7 +850,7 @@ export const servicePatches: Record<string, ServicePatches> = {
805850

806851
// ========== Snapshot Operations ==========
807852
CopySnapshot: {
808-
errors: ["InvalidSnapshot.NotFound", "InvalidSnapshotId.Malformed"],
853+
errors: ["InvalidSnapshot.NotFound", "InvalidSnapshotID.Malformed"],
809854
},
810855
CreateSnapshot: {
811856
errors: ["InvalidVolume.NotFound"],
@@ -817,14 +862,14 @@ export const servicePatches: Record<string, ServicePatches> = {
817862
errors: [
818863
"InvalidSnapshot.NotFound",
819864
"InvalidSnapshot.InUse",
820-
"InvalidSnapshotId.Malformed",
865+
"InvalidSnapshotID.Malformed",
821866
],
822867
},
823868
DescribeSnapshotAttribute: {
824-
errors: ["InvalidSnapshot.NotFound", "InvalidSnapshotId.Malformed"],
869+
errors: ["InvalidSnapshot.NotFound", "InvalidSnapshotID.Malformed"],
825870
},
826871
DescribeSnapshots: {
827-
errors: ["InvalidSnapshot.NotFound", "InvalidSnapshotId.Malformed"],
872+
errors: ["InvalidSnapshot.NotFound", "InvalidSnapshotID.Malformed"],
828873
},
829874
ModifySnapshotAttribute: {
830875
errors: ["InvalidSnapshot.NotFound"],
@@ -885,7 +930,7 @@ export const servicePatches: Record<string, ServicePatches> = {
885930
errors: ["InvalidSubnetID.NotFound"],
886931
},
887932
DeleteSubnet: {
888-
errors: ["InvalidSubnetID.NotFound"],
933+
errors: ["InvalidSubnetID.NotFound", "InvalidSubnetId.Malformed"],
889934
},
890935
DeleteSubnetCidrReservation: {
891936
errors: ["InvalidSubnetCidrReservationId.NotFound"],
@@ -1265,13 +1310,21 @@ export const servicePatches: Record<string, ServicePatches> = {
12651310
],
12661311
},
12671312
DeleteVolume: {
1268-
errors: ["InvalidVolume.NotFound", "InvalidVolumeID.Malformed"],
1313+
errors: [
1314+
"InvalidVolume.NotFound",
1315+
"InvalidVolumeID.Malformed",
1316+
"InvalidParameterValue",
1317+
],
12691318
},
12701319
DescribeVolumeAttribute: {
12711320
errors: ["InvalidVolume.NotFound", "InvalidVolumeID.Malformed"],
12721321
},
12731322
DescribeVolumes: {
1274-
errors: ["InvalidVolume.NotFound", "InvalidVolumeID.Malformed"],
1323+
errors: [
1324+
"InvalidVolume.NotFound",
1325+
"InvalidVolumeID.Malformed",
1326+
"InvalidParameterValue",
1327+
],
12751328
},
12761329
DescribeVolumesModifications: {
12771330
errors: ["InvalidVolume.NotFound"],
@@ -1487,6 +1540,20 @@ export const servicePatches: Record<string, ServicePatches> = {
14871540
"InvalidVpnGatewayAttachment.NotFound",
14881541
],
14891542
},
1543+
DisableVgwRoutePropagation: {
1544+
errors: [
1545+
"InvalidRouteTableID.NotFound",
1546+
"InvalidVpnGatewayID.NotFound",
1547+
"Gateway.NotAttached",
1548+
],
1549+
},
1550+
EnableVgwRoutePropagation: {
1551+
errors: [
1552+
"InvalidRouteTableID.NotFound",
1553+
"InvalidVpnGatewayID.NotFound",
1554+
"Gateway.NotAttached",
1555+
],
1556+
},
14901557

14911558
// ========== Egress-Only Internet Gateway Operations ==========
14921559
CreateEgressOnlyInternetGateway: {

0 commit comments

Comments
 (0)