From b816018150b71255f46c812fd8db0350f08ad01f Mon Sep 17 00:00:00 2001 From: Siddhant Date: Mon, 5 Feb 2024 15:07:05 -0600 Subject: [PATCH] improve(r2): Update Sippy endpoint request payloads to match new schema --- .changeset/five-cooks-share.md | 5 ++ packages/wrangler/src/__tests__/r2.test.ts | 58 ++++++++++------- packages/wrangler/src/r2/helpers.ts | 39 ++++++------ packages/wrangler/src/r2/sippy.ts | 74 +++++++++++++--------- 4 files changed, 103 insertions(+), 73 deletions(-) create mode 100644 .changeset/five-cooks-share.md diff --git a/.changeset/five-cooks-share.md b/.changeset/five-cooks-share.md new file mode 100644 index 000000000000..412081cda802 --- /dev/null +++ b/.changeset/five-cooks-share.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +Update API calls for Sippy's endpoints diff --git a/packages/wrangler/src/__tests__/r2.test.ts b/packages/wrangler/src/__tests__/r2.test.ts index f562da7caa24..91aa05adfd34 100644 --- a/packages/wrangler/src/__tests__/r2.test.ts +++ b/packages/wrangler/src/__tests__/r2.test.ts @@ -25,7 +25,7 @@ describe("r2", () => { runWrangler("r2 bucket foo") ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown argument: foo"`); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Unknown argument: foo + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mUnknown argument: foo�[0m " `); @@ -117,7 +117,7 @@ describe("r2", () => { -J, --jurisdiction The jurisdiction where the new bucket will be created [string]" `); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Not enough non-option arguments: got 0, need at least 1 + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mNot enough non-option arguments: got 0, need at least 1�[0m " `); @@ -149,7 +149,7 @@ describe("r2", () => { -J, --jurisdiction The jurisdiction where the new bucket will be created [string]" `); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Unknown arguments: def, ghi + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mUnknown arguments: def, ghi�[0m " `); @@ -222,7 +222,7 @@ describe("r2", () => { -J, --jurisdiction The jurisdiction where the bucket exists [string]" `); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Not enough non-option arguments: got 0, need at least 1 + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mNot enough non-option arguments: got 0, need at least 1�[0m " `); @@ -254,7 +254,7 @@ describe("r2", () => { -J, --jurisdiction The jurisdiction where the bucket exists [string]" `); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Unknown arguments: def, ghi + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mUnknown arguments: def, ghi�[0m " `); @@ -293,7 +293,7 @@ describe("r2", () => { runWrangler("r2 bucket sippy foo") ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown argument: foo"`); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Unknown argument: foo + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mUnknown argument: foo�[0m " `); @@ -326,19 +326,24 @@ describe("r2", () => { "*/accounts/some-account-id/r2/buckets/testBucket/sippy", async (request, response, context) => { expect(await request.json()).toEqual({ - access_key: "aws-secret", - bucket: "awsBucket", - key_id: "aws-key", - provider: "AWS", - r2_access_key: "some-secret", - r2_key_id: "some-key", + source: { + provider: "aws", + bucket: "awsBucket", + accessKeyId: "aws-key", + secretAccessKey: "aws-secret", + }, + destination: { + provider: "r2", + accessKeyId: "some-key", + secretAccessKey: "some-secret", + }, }); return response.once(context.json(createFetchResult({}))); } ) ); await runWrangler( - "r2 bucket sippy enable testBucket --r2-key-id=some-key --r2-secret-access-key=some-secret --provider=AWS --key-id=aws-key --secret-access-key=aws-secret --bucket=awsBucket" + "r2 bucket sippy enable testBucket --r2-access-key-id=some-key --r2-secret-access-key=some-secret --provider=AWS --key-id=aws-key --secret-access-key=aws-secret --bucket=awsBucket" ); expect(std.out).toMatchInlineSnapshot( `"✨ Successfully enabled Sippy on the 'testBucket' bucket."` @@ -353,19 +358,24 @@ describe("r2", () => { "*/accounts/some-account-id/r2/buckets/testBucket/sippy", async (request, response, context) => { expect(await request.json()).toEqual({ - private_key: "gcs-private-key", - bucket: "gcsBucket", - client_email: "gcs-client-email", - provider: "GCS", - r2_access_key: "some-secret", - r2_key_id: "some-key", + source: { + provider: "gcs", + bucket: "gcsBucket", + clientEmail: "gcs-client-email", + privateKey: "gcs-private-key", + }, + destination: { + provider: "r2", + accessKeyId: "some-key", + secretAccessKey: "some-secret", + }, }); return response.once(context.json(createFetchResult({}))); } ) ); await runWrangler( - "r2 bucket sippy enable testBucket --r2-key-id=some-key --r2-secret-access-key=some-secret --provider=GCS --client-email=gcs-client-email --private-key=gcs-private-key --bucket=gcsBucket" + "r2 bucket sippy enable testBucket --r2-access-key-id=some-key --r2-secret-access-key=some-secret --provider=GCS --client-email=gcs-client-email --private-key=gcs-private-key --bucket=gcsBucket" ); expect(std.out).toMatchInlineSnapshot( `"✨ Successfully enabled Sippy on the 'testBucket' bucket."` @@ -408,7 +418,7 @@ describe("r2", () => { --r2-secret-access-key The secret access key for this R2 bucket [string]" `); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Not enough non-option arguments: got 0, need at least 1 + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mNot enough non-option arguments: got 0, need at least 1�[0m " `); @@ -442,7 +452,7 @@ describe("r2", () => { -J, --jurisdiction The jurisdiction where the bucket exists [string]" `); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Not enough non-option arguments: got 0, need at least 1 + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mNot enough non-option arguments: got 0, need at least 1�[0m " `); @@ -493,7 +503,7 @@ describe("r2", () => { -J, --jurisdiction The jurisdiction where the bucket exists [string]" `); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Not enough non-option arguments: got 0, need at least 1 + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mNot enough non-option arguments: got 0, need at least 1�[0m " `); @@ -658,7 +668,7 @@ describe("r2", () => { ); expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Arguments pipe and file are mutually exclusive + "�[31mX �[41;31m[�[41;97mERROR�[41;31m]�[0m �[1mArguments pipe and file are mutually exclusive�[0m " `); diff --git a/packages/wrangler/src/r2/helpers.ts b/packages/wrangler/src/r2/helpers.ts index 5acee6e6bafb..f96202c80758 100644 --- a/packages/wrangler/src/r2/helpers.ts +++ b/packages/wrangler/src/r2/helpers.ts @@ -260,26 +260,27 @@ export async function deleteR2Sippy( ); } -export type R2Credentials = { - bucket: string; - r2_key_id: string; - r2_access_key: string; -}; - -export type SippyPutConfig = R2Credentials & - ( +export type SippyPutConfig = { + source: | { - provider: "AWS"; - zone: string | undefined; - key_id: string; - access_key: string; + provider: "aws"; + region: string; + bucket: string; + accessKeyId: string; + secretAccessKey: string; } | { - provider: "GCS"; - client_email: string; - private_key: string; - } - ); + provider: "gcs"; + bucket: string; + clientEmail: string; + privateKey: string; + }; + destination: { + provider: "r2"; + accessKeyId: string; + secretAccessKey: string; + }; +}; /** * Enable sippy on the bucket with the given name @@ -290,7 +291,9 @@ export async function putR2Sippy( config: SippyPutConfig, jurisdiction?: string ): Promise { - const headers: HeadersInit = {}; + const headers: HeadersInit = { + "Content-Type": "application/json", + }; if (jurisdiction !== undefined) { headers["cf-r2-jurisdiction"] = jurisdiction; } diff --git a/packages/wrangler/src/r2/sippy.ts b/packages/wrangler/src/r2/sippy.ts index 1a04d7a83d00..2594a7269638 100644 --- a/packages/wrangler/src/r2/sippy.ts +++ b/packages/wrangler/src/r2/sippy.ts @@ -12,7 +12,7 @@ import type { import type { SippyPutConfig } from "./helpers"; const NO_SUCH_OBJECT_KEY = 10007; -const SIPPY_PROVIDER_CHOICES = ["AWS", "GCS"]; +const SIPPY_PROVIDER_CHOICES = ["aws", "gcs"]; export function EnableOptions(yargs: CommonYargsArgv) { return yargs @@ -38,7 +38,7 @@ export function EnableOptions(yargs: CommonYargsArgv) { description: "(AWS provider only) The region of the upstream bucket", string: true, }) - .option("key-id", { + .option("access-key-id", { description: "(AWS provider only) The secret access key id for the upstream bucket", string: true, @@ -63,7 +63,7 @@ export function EnableOptions(yargs: CommonYargsArgv) { "(GCS provider only) The private key for your Google Cloud service account key", string: true, }) - .option("r2-key-id", { + .option("r2-access-key-id", { description: "The secret access key id for this R2 bucket", string: true, }) @@ -97,14 +97,14 @@ export async function EnableHandler( throw new UserError(`Must specify ${args.provider} bucket name.`); } - if (args.provider == "AWS") { + if (args.provider === "AWS") { args.region ??= await prompt( "Enter the AWS region where your S3 bucket is located (example: us-west-2):" ); - args.keyId ??= await prompt( + args.accessKeyId ??= await prompt( "Enter your AWS Access Key ID (requires read and list access):" ); - if (!args.keyId) { + if (!args.accessKeyId) { throw new UserError("Must specify an AWS Access Key ID."); } args.secretAccessKey ??= await prompt( @@ -113,7 +113,7 @@ export async function EnableHandler( if (!args.secretAccessKey) { throw new UserError("Must specify an AWS Secret Access Key."); } - } else if (args.provider == "GCS") { + } else if (args.provider === "GCS") { if ( !(args.clientEmail && args.privateKey) && !args.serviceAccountKeyFile @@ -129,10 +129,10 @@ export async function EnableHandler( } } - args.r2KeyId ??= await prompt( + args.r2AccessKeyId ??= await prompt( "Enter your R2 Access Key ID (requires read and write access):" ); - if (!args.r2KeyId) { + if (!args.r2AccessKeyId) { throw new UserError("Must specify an R2 Access Key ID."); } args.r2SecretAccessKey ??= await prompt("Enter your R2 Secret Access Key:"); @@ -141,46 +141,58 @@ export async function EnableHandler( } } - let sippyConfig = { - bucket: args.bucket ?? "", - r2_key_id: args.r2KeyId ?? "", - r2_access_key: args.r2SecretAccessKey ?? "", - } as SippyPutConfig; + let sippyConfig: SippyPutConfig; - if (args.provider == "AWS") { - if (!(args.keyId && args.secretAccessKey)) { + if (args.provider === "AWS") { + if (!(args.accessKeyId && args.secretAccessKey)) { throw new UserError( - `Error: must provide --key-id and --secret-access-key.` + "Error: must provide --access-key-id and --secret-access-key." ); } + sippyConfig = { - ...sippyConfig, - provider: "AWS", - zone: args.region, - key_id: args.keyId, - access_key: args.secretAccessKey, + source: { + provider: "aws", + region: args.region, + bucket: args.bucket, + accessKeyId: args.accessKeyId, + secretAccessKey: args.secretAccessKey, + }, + destination: { + provider: "r2", + accessKeyId: args.r2AccessKeyId, + secretAccessKey: args.r2SecretAccessKey, + }, }; - } else if (args.provider == "GCS") { + } else if (args.provider === "GCS") { if (args.serviceAccountKeyFile) { const serviceAccount = JSON.parse( readFileSync(args.serviceAccountKeyFile) ); if ("client_email" in serviceAccount && "private_key" in serviceAccount) { - args.clientEmail = serviceAccount["client_email"]; - args.privateKey = serviceAccount["private_key"]; + args.clientEmail = serviceAccount.client_email; + args.privateKey = serviceAccount.private_key; } } if (!(args.clientEmail && args.privateKey)) { throw new UserError( - `Error: must provide --service-account-key-file or --client-email and --private-key.` + "Error: must provide --service-account-key-file or --client-email and --private-key." ); } args.privateKey = args.privateKey.replace(/\\n/g, "\n"); + sippyConfig = { - ...sippyConfig, - provider: "GCS", - client_email: args.clientEmail, - private_key: args.privateKey, + source: { + provider: "gcs", + bucket: args.bucket, + clientEmail: args.clientEmail, + privateKey: args.privateKey, + }, + destination: { + provider: "r2", + accessKeyId: args.r2AccessKeyId, + secretAccessKey: args.r2SecretAccessKey, + }, }; } @@ -218,7 +230,7 @@ export async function GetHandler( ); logger.log(`Sippy upstream bucket: ${sippyBucket}.`); } catch (e) { - if (e instanceof APIError && "code" in e && e.code == NO_SUCH_OBJECT_KEY) { + if (e instanceof APIError && "code" in e && e.code === NO_SUCH_OBJECT_KEY) { logger.log(`No Sippy configuration found for the '${args.name}' bucket.`); } else { throw e;