| 1 | import * as AWS from "@/AWS"; |
| 2 | import { LogGroup } from "@/AWS/Logs"; |
| 3 | import { AccessLogSubscription, ServiceNetwork } from "@/AWS/VpcLattice"; |
| 4 | import * as Test from "@/Test/Alchemy"; |
| 5 | import * as vpclattice from "@distilled.cloud/aws/vpc-lattice"; |
| 6 | import { expect } from "alchemy-test"; |
| 7 | import * as Effect from "effect/Effect"; |
| 8 | |
| 9 | const { test } = Test.make({ providers: AWS.providers() }); |
| 10 | |
| 11 | // CloudWatch log-group destination ARNs round-trip through the lattice API |
| 12 | // with a trailing `:*`. |
| 13 | const normalizeArn = (arn: string) => arn.replace(/:\*$/, ""); |
| 14 | |
| 15 | test.provider( |
| 16 | "create, update destination, delete an access log subscription", |
| 17 | (stack) => |
| 18 | Effect.gen(function* () { |
| 19 | yield* stack.destroy(); |
| 20 | |
| 21 | const program = (destination: "primary" | "secondary") => |
| 22 | Effect.gen(function* () { |
| 23 | const network = yield* ServiceNetwork("LogsNetwork", {}); |
| 24 | const primary = yield* LogGroup("LatticeLogsPrimary", { |
| 25 | retention: "1 days", |
| 26 | }); |
| 27 | const secondary = yield* LogGroup("LatticeLogsSecondary", { |
| 28 | retention: "1 days", |
| 29 | }); |
| 30 | const subscription = yield* AccessLogSubscription("NetworkLogs", { |
| 31 | resourceIdentifier: network.serviceNetworkId, |
| 32 | destinationArn: |
| 33 | destination === "primary" |
| 34 | ? primary.logGroupArn |
| 35 | : secondary.logGroupArn, |
| 36 | }); |
| 37 | return { network, primary, secondary, subscription }; |
| 38 | }); |
| 39 | |
| 40 | const first = yield* stack.deploy(program("primary")); |
| 41 | |
| 42 | expect(first.subscription.accessLogSubscriptionId).toMatch(/^als-/); |
| 43 | expect(normalizeArn(first.subscription.destinationArn)).toBe( |
| 44 | normalizeArn(first.primary.logGroupArn), |
| 45 | ); |
| 46 | |
| 47 | const live = yield* vpclattice.getAccessLogSubscription({ |
| 48 | accessLogSubscriptionIdentifier: |
| 49 | first.subscription.accessLogSubscriptionId, |
| 50 | }); |
| 51 | expect(normalizeArn(live.destinationArn)).toBe( |
| 52 | normalizeArn(first.primary.logGroupArn), |
| 53 | ); |
| 54 | expect(live.resourceId).toBe(first.network.serviceNetworkId); |
| 55 | |
| 56 | // Update the destination in place (same destination type). |
| 57 | const second = yield* stack.deploy(program("secondary")); |
| 58 | expect(second.subscription.accessLogSubscriptionId).toBe( |
| 59 | first.subscription.accessLogSubscriptionId, |
| 60 | ); |
| 61 | const updated = yield* vpclattice.getAccessLogSubscription({ |
| 62 | accessLogSubscriptionIdentifier: |
| 63 | first.subscription.accessLogSubscriptionId, |
| 64 | }); |
| 65 | expect(normalizeArn(updated.destinationArn)).toBe( |
| 66 | normalizeArn(first.secondary.logGroupArn), |
| 67 | ); |
| 68 | |
| 69 | yield* stack.destroy(); |
| 70 | const gone = yield* vpclattice |
| 71 | .getAccessLogSubscription({ |
| 72 | accessLogSubscriptionIdentifier: |
| 73 | first.subscription.accessLogSubscriptionId, |
| 74 | }) |
| 75 | .pipe( |
| 76 | Effect.map(() => false), |
| 77 | Effect.catchTag("ResourceNotFoundException", () => |
| 78 | Effect.succeed(true), |
| 79 | ), |
| 80 | ); |
| 81 | expect(gone).toBe(true); |
| 82 | }).pipe(Effect.ensuring(Effect.ignore(stack.destroy()))), |
| 83 | { |
| 84 | tags: [ |
| 85 | "provider:aws", |
| 86 | "provider:aws:logs", |
| 87 | "provider:aws:vpclattice", |
| 88 | "live", |
| 89 | ], |
| 90 | timeout: 300_000, |
| 91 | }, |
| 92 | ); |