From 6b9735389fcb57dd8abb778439dd5e11f593b264 Mon Sep 17 00:00:00 2001 From: bthwaites Date: Tue, 22 Oct 2024 06:09:57 -0400 Subject: [PATCH] Add jurisdiction option to R2 event notification wrangler actions (#6945) --- .changeset/tasty-jeans-train.md | 5 ++ packages/wrangler/src/__tests__/r2.test.ts | 14 ++++-- .../wrangler/src/__tests__/r2/helpers.test.ts | 5 +- packages/wrangler/src/r2/helpers.ts | 17 +++++-- packages/wrangler/src/r2/notification.ts | 46 +++++++++++++++---- 5 files changed, 68 insertions(+), 19 deletions(-) create mode 100644 .changeset/tasty-jeans-train.md diff --git a/.changeset/tasty-jeans-train.md b/.changeset/tasty-jeans-train.md new file mode 100644 index 000000000000..1b2620b3e72c --- /dev/null +++ b/.changeset/tasty-jeans-train.md @@ -0,0 +1,5 @@ +--- +"wrangler": minor +--- + +Add jurisdiction option to R2 event notification wrangler actions diff --git a/packages/wrangler/src/__tests__/r2.test.ts b/packages/wrangler/src/__tests__/r2.test.ts index 08304e59dc64..4bad79554958 100644 --- a/packages/wrangler/src/__tests__/r2.test.ts +++ b/packages/wrangler/src/__tests__/r2.test.ts @@ -912,7 +912,10 @@ describe("r2", () => { -c, --config Path to .toml configuration file [string] -e, --env Environment to use for operations and .env files [string] -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -v, --version Show version number [boolean] + + OPTIONS + -J, --jurisdiction The jurisdiction where the bucket exists [string]" `); }); }); @@ -1024,7 +1027,8 @@ describe("r2", () => { --event-types, --event-type The type of event(s) that will emit event notifications [array] [required] [choices: \\"object-create\\", \\"object-delete\\"] --prefix The prefix that an object must match to emit event notifications (note: regular expressions not supported) [string] --suffix The suffix that an object must match to emit event notifications (note: regular expressions not supported) [string] - --queue The name of the queue that will receive event notification messages [string] [required]" + --queue The name of the queue that will receive event notification messages [string] [required] + -J, --jurisdiction The jurisdiction where the bucket exists [string]" `); }); }); @@ -1178,8 +1182,10 @@ describe("r2", () => { -v, --version Show version number [boolean] OPTIONS - --queue The name of the queue that corresponds to the event notification rule. If no rule is provided, all event notification rules associated with the bucket and queue will be deleted [string] [required] - --rule The ID of the event notification rule to delete [string]" + --queue The name of the queue that corresponds to the event notification rule. If no rule is provided, all event notification rules associated with the bucket and queue will be deleted [string] [required] + --rule The ID of the event notification rule to delete [string] + -J, --jurisdiction The jurisdiction where the bucket exists [string]" + `); }); }); diff --git a/packages/wrangler/src/__tests__/r2/helpers.test.ts b/packages/wrangler/src/__tests__/r2/helpers.test.ts index 49d950baa2d2..1437b7f7145d 100644 --- a/packages/wrangler/src/__tests__/r2/helpers.test.ts +++ b/packages/wrangler/src/__tests__/r2/helpers.test.ts @@ -82,7 +82,7 @@ describe("event notifications", () => { authEmail: "test@example.com", authKey: "some-big-secret", }; - const result = eventNotificationHeaders(creds); + const result = eventNotificationHeaders(creds, ""); expect(result).toMatchObject({ "X-Auth-Key": creds.authKey, "X-Auth-Email": creds.authEmail, @@ -91,9 +91,10 @@ describe("event notifications", () => { test("API token eventNotificationHeaders", () => { const creds: ApiCredentials = { apiToken: "some-api-token" }; - const result = eventNotificationHeaders(creds); + const result = eventNotificationHeaders(creds, "eu"); expect(result).toMatchObject({ Authorization: `Bearer ${creds.apiToken}`, + "cf-r2-jurisdiction": "eu", }); }); }); diff --git a/packages/wrangler/src/r2/helpers.ts b/packages/wrangler/src/r2/helpers.ts index afebf7f2f13d..ee1f33aee9e8 100644 --- a/packages/wrangler/src/r2/helpers.ts +++ b/packages/wrangler/src/r2/helpers.ts @@ -423,7 +423,8 @@ export type DeleteNotificationRequestBody = { }; export function eventNotificationHeaders( - apiCredentials: ApiCredentials + apiCredentials: ApiCredentials, + jurisdiction: string ): HeadersInit { const headers: HeadersInit = { "Content-Type": "application/json", @@ -435,6 +436,9 @@ export function eventNotificationHeaders( headers["X-Auth-Key"] = apiCredentials.authKey; headers["X-Auth-Email"] = apiCredentials.authEmail; } + if (jurisdiction !== "") { + headers["cf-r2-jurisdiction"] = jurisdiction; + } return headers; } @@ -486,9 +490,10 @@ export async function tableFromNotificationGetResponse( export async function listEventNotificationConfig( apiCredentials: ApiCredentials, accountId: string, - bucketName: string + bucketName: string, + jurisdiction: string ): Promise { - const headers = eventNotificationHeaders(apiCredentials); + const headers = eventNotificationHeaders(apiCredentials, jurisdiction); logger.log(`Fetching notification rules for bucket ${bucketName}...`); const res = await fetchResult( `/accounts/${accountId}/event_notifications/r2/${bucketName}/configuration`, @@ -541,13 +546,14 @@ export async function putEventNotificationConfig( apiCredentials: ApiCredentials, accountId: string, bucketName: string, + jurisdiction: string, queueName: string, eventTypes: R2EventType[], prefix?: string, suffix?: string ): Promise { const queue = await getQueue(config, queueName); - const headers = eventNotificationHeaders(apiCredentials); + const headers = eventNotificationHeaders(apiCredentials, jurisdiction); let actions: R2EventableOperation[] = []; for (const et of eventTypes) { @@ -576,11 +582,12 @@ export async function deleteEventNotificationConfig( apiCredentials: ApiCredentials, accountId: string, bucketName: string, + jurisdiction: string, queueName: string, ruleId: string | undefined ): Promise { const queue = await getQueue(config, queueName); - const headers = eventNotificationHeaders(apiCredentials); + const headers = eventNotificationHeaders(apiCredentials, jurisdiction); if (ruleId !== undefined) { logger.log(`Deleting event notifications rule "${ruleId}"...`); const body: DeleteNotificationRequestBody = diff --git a/packages/wrangler/src/r2/notification.ts b/packages/wrangler/src/r2/notification.ts index 263d7a5b645e..15d7b7fd6328 100644 --- a/packages/wrangler/src/r2/notification.ts +++ b/packages/wrangler/src/r2/notification.ts @@ -17,11 +17,18 @@ import type { import type { R2EventType } from "./helpers"; export function ListOptions(yargs: CommonYargsArgv) { - return yargs.positional("bucket", { - describe: "The name of the R2 bucket to get event notification rules for", - type: "string", - demandOption: true, - }); + return yargs + .positional("bucket", { + describe: "The name of the R2 bucket to get event notification rules for", + type: "string", + demandOption: true, + }) + .option("jurisdiction", { + describe: "The jurisdiction where the bucket exists", + alias: "J", + requiresArg: true, + type: "string", + }); } export async function ListHandler( @@ -37,10 +44,12 @@ export async function ListHandler( const config = readConfig(args.config, args); const accountId = await requireAuth(config); const apiCreds = requireApiToken(); + const { bucket, jurisdiction = "" } = args; const resp = await listEventNotificationConfig( apiCreds, accountId, - `${args.bucket}` + bucket, + jurisdiction ); const tableOutput = await tableFromNotificationGetResponse(config, resp); logger.log(tableOutput.map((x) => formatLabelledValues(x)).join("\n\n")); @@ -79,6 +88,12 @@ export function CreateOptions(yargs: CommonYargsArgv) { demandOption: true, requiresArg: true, type: "string", + }) + .option("jurisdiction", { + describe: "The jurisdiction where the bucket exists", + alias: "J", + requiresArg: true, + type: "string", }); } @@ -89,12 +104,20 @@ export async function CreateHandler( const config = readConfig(args.config, args); const accountId = await requireAuth(config); const apiCreds = requireApiToken(); - const { bucket, queue, eventTypes, prefix = "", suffix = "" } = args; + const { + bucket, + queue, + eventTypes, + prefix = "", + suffix = "", + jurisdiction = "", + } = args; await putEventNotificationConfig( config, apiCreds, accountId, bucket, + jurisdiction, queue, eventTypes as R2EventType[], prefix, @@ -122,6 +145,12 @@ export function DeleteOptions(yargs: CommonYargsArgv) { describe: "The ID of the event notification rule to delete", requiresArg: false, type: "string", + }) + .option("jurisdiction", { + describe: "The jurisdiction where the bucket exists", + alias: "J", + requiresArg: true, + type: "string", }); } @@ -132,12 +161,13 @@ export async function DeleteHandler( const config = readConfig(args.config, args); const accountId = await requireAuth(config); const apiCreds = requireApiToken(); - const { bucket, queue, rule } = args; + const { bucket, queue, rule, jurisdiction = "" } = args; await deleteEventNotificationConfig( config, apiCreds, accountId, bucket, + jurisdiction, queue, rule );