1import * as AWS from "@/AWS";
2import { DhcpOptions, Vpc } from "@/AWS/EC2";
3import * as Provider from "@/Provider";
4import * as Test from "./VpcTest.ts";
5import * as EC2 from "@distilled.cloud/aws/ec2";
6import { expect } from "alchemy-test";
7import * as Data from "effect/Data";
8import * as Effect from "effect/Effect";
9import { MinimumLogLevel } from "effect/References";
10import * as Schedule from "effect/Schedule";
11
12const { test } = Test.make({ providers: AWS.providers() });
13
14const logLevel = Effect.provideService(
15 MinimumLogLevel,
16 process.env.DEBUG ? "Debug" : "Info",
17);
18
19class DhcpOptionsStillExists extends Data.TaggedError(
20 "DhcpOptionsStillExists",
21) {}
22
23const assertDeleted = Effect.fn(function* (dhcpOptionsId: string) {
24 yield* EC2.describeDhcpOptions({ DhcpOptionsIds: [dhcpOptionsId] }).pipe(
25 Effect.flatMap((r) =>
26 (r.DhcpOptions?.length ?? 0) === 0
27 ? Effect.void
28 : Effect.fail(new DhcpOptionsStillExists()),
29 ),
30 Effect.retry({
31 while: (e) => e instanceof DhcpOptionsStillExists,
32 schedule: Schedule.max([Schedule.exponential(300), Schedule.recurs(8)]),
33 }),
34 Effect.catchTag("InvalidDhcpOptionID.NotFound", () => Effect.void),
35 Effect.catchTag("InvalidDhcpOptionsID.NotFound", () => Effect.void),
36 );
37});
38
39test.provider(
40 "create DHCP options set, associate to VPC, delete",
41 (stack) =>
42 Effect.gen(function* () {
43 yield* stack.destroy();
44
45 const { vpc, dhcp } = yield* stack.deploy(
46 Effect.gen(function* () {
47 const vpc = yield* Vpc("DhcpVpc", { cidrBlock: "10.60.0.0/16" });
48 const dhcp = yield* DhcpOptions("Dhcp", {
49 domainName: "corp.internal",
50 domainNameServers: ["AmazonProvidedDNS"],
51 netbiosNodeType: "2",
52 vpcId: vpc.vpcId,
53 });
54 return { vpc, dhcp };
55 }),
56 );
57
58 expect(dhcp.dhcpOptionsId).toMatch(/^dopt-/);
59 expect(dhcp.vpcId).toEqual(vpc.vpcId);
60
61 // Verify out-of-band: the options set exists with the domain config.
62 const described = yield* EC2.describeDhcpOptions({
63 DhcpOptionsIds: [dhcp.dhcpOptionsId],
64 });
65 const opts = described.DhcpOptions?.[0];
66 expect(opts?.DhcpOptionsId).toEqual(dhcp.dhcpOptionsId);
67 const domainNameConfig = opts?.DhcpConfigurations?.find(
68 (c) => c.Key === "domain-name",
69 );
70 expect(domainNameConfig?.Values?.[0]?.Value).toEqual("corp.internal");
71
72 // Verify the VPC points at the options set.
73 const vpcs = yield* EC2.describeVpcs({ VpcIds: [vpc.vpcId] });
74 expect(vpcs.Vpcs?.[0]?.DhcpOptionsId).toEqual(dhcp.dhcpOptionsId);
75
76 yield* stack.destroy();
77 yield* assertDeleted(dhcp.dhcpOptionsId);
78 }).pipe(logLevel),
79 { tags: ["provider:aws", "provider:aws:ec2", "live"], timeout: 240_000 },
80);
81
82test.provider(
83 "list enumerates the deployed DHCP options set",
84 (stack) =>
85 Effect.gen(function* () {
86 yield* stack.destroy();
87
88 const { dhcp } = yield* stack.deploy(
89 Effect.gen(function* () {
90 const dhcp = yield* DhcpOptions("ListDhcp", {
91 domainNameServers: ["AmazonProvidedDNS"],
92 });
93 return { dhcp };
94 }),
95 );
96
97 const provider = yield* Provider.findProvider(DhcpOptions);
98 const all = yield* provider.list();
99 expect(all.some((x) => x.dhcpOptionsId === dhcp.dhcpOptionsId)).toBe(
100 true,
101 );
102
103 yield* stack.destroy();
104 yield* assertDeleted(dhcp.dhcpOptionsId);
105 }).pipe(logLevel),
106 { tags: ["provider:aws", "provider:aws:ec2", "live"], timeout: 240_000 },
107);