1import { VpcId } from "@/AWS/EC2";
2import * as EC2 from "@distilled.cloud/aws/ec2";
3import * as Data from "effect/Data";
4import * as Effect from "effect/Effect";
5import * as Schedule from "effect/Schedule";
6
7class DefaultVpcNotVisible extends Data.TaggedError(
8 "DefaultVpcNotVisible",
9)<{}> {}
10
11class DefaultVpcNetworkNotVisible extends Data.TaggedError(
12 "DefaultVpcNetworkNotVisible",
13)<{}> {}
14
15class UnsupportedDefaultVpcCidr extends Data.TaggedError(
16 "UnsupportedDefaultVpcCidr",
17)<{
18 readonly cidrBlock: string;
19}> {}
20
21export const getDefaultVpc = Effect.gen(function* () {
22 const vpcs = yield* EC2.describeVpcs({});
23 const vpc = (vpcs.Vpcs ?? []).find((v) => v.IsDefault);
24 if (!vpc?.VpcId || !vpc.CidrBlock) {
25 // The default VPC can be deleted out of band (e.g. by the account nuke
26 // script). Recreate it, then fail with the retryable marker so the retry
27 // loop below re-describes until it becomes visible. Concurrent test files
28 // racing on the same recreate surface DefaultVpcAlreadyExists — that just
29 // means someone else won the race, so fall through to the retry.
30 yield* EC2.createDefaultVpc({}).pipe(
31 Effect.catchTag("DefaultVpcAlreadyExists", () => Effect.void),
32 );
33 return yield* Effect.fail(new DefaultVpcNotVisible());
34 }
35
36 const [baseAddress, prefixString] = vpc.CidrBlock.split("/");
37 if (prefixString !== "16") {
38 return yield* Effect.fail(
39 new UnsupportedDefaultVpcCidr({ cidrBlock: vpc.CidrBlock }),
40 );
41 }
42
43 const [a, b] = baseAddress.split(".");
44 return {
45 vpcId: VpcId(vpc.VpcId),
46 cidrBlock: vpc.CidrBlock,
47 subnetCidrBlock: (thirdOctet: number) => `${a}.${b}.${thirdOctet}.0/24`,
48 };
49}).pipe(
50 Effect.retry({
51 while: (e) => e._tag === "DefaultVpcNotVisible",
52 schedule: Schedule.max([Schedule.spaced("3 seconds"), Schedule.recurs(10)]),
53 }),
54);
55
56/** Wait for the default VPC's generated subnets and security group as well. */
57export const getDefaultVpcNetwork = Effect.gen(function* () {
58 const vpc = yield* getDefaultVpc;
59 const [subnets, groups] = yield* Effect.all(
60 [
61 EC2.describeSubnets({
62 Filters: [{ Name: "vpc-id", Values: [vpc.vpcId] }],
63 } as any),
64 EC2.describeSecurityGroups({
65 Filters: [
66 { Name: "vpc-id", Values: [vpc.vpcId] },
67 { Name: "group-name", Values: ["default"] },
68 ],
69 } as any),
70 ],
71 { concurrency: 2 },
72 );
73 const subnetIds = (subnets.Subnets ?? [])
74 .flatMap((subnet) => (subnet.SubnetId ? [subnet.SubnetId] : []))
75 .sort();
76 const defaultSecurityGroupId = groups.SecurityGroups?.[0]?.GroupId;
77 if (subnetIds.length === 0 || !defaultSecurityGroupId) {
78 return yield* Effect.fail(new DefaultVpcNetworkNotVisible());
79 }
80 return { ...vpc, subnetIds, defaultSecurityGroupId };
81}).pipe(
82 Effect.retry({
83 while: (error) => error._tag === "DefaultVpcNetworkNotVisible",
84 schedule: Schedule.max([Schedule.fixed("1 second"), Schedule.recurs(30)]),
85 }),
86);