Skip to content

Commit

Permalink
R2: Add Sippy support (#4130)
Browse files Browse the repository at this point in the history
  • Loading branch information
vkrasnov committed Dec 18, 2023
1 parent 2ddef2a commit e8a2a1d
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/fluffy-sheep-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": minor
---

Added support for R2 Sippy incremental migration
1 change: 1 addition & 0 deletions packages/wrangler/src/__tests__/r2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ describe("r2", () => {
wrangler r2 bucket create <name> Create a new R2 bucket
wrangler r2 bucket list List R2 buckets
wrangler r2 bucket delete <name> Delete an R2 bucket
wrangler r2 bucket sippy Manage Sippy incremental migration on an R2 bucket
Flags:
-j, --experimental-json-config Experimental: Support wrangler.json [boolean]
Expand Down
63 changes: 63 additions & 0 deletions packages/wrangler/src/r2/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,66 @@ export async function usingLocalBucket<T>(
await mf.dispose();
}
}

/**
* Retreive the sippy upstream bucket for the bucket with the given name
*/
export async function getR2Sippy(
accountId: string,
bucketName: string,
jurisdiction?: string
): Promise<string> {
const headers: HeadersInit = {};
if (jurisdiction !== undefined) {
headers["cf-r2-jurisdiction"] = jurisdiction;
}
return await fetchResult(
`/accounts/${accountId}/r2/buckets/${bucketName}/sippy`,
{ method: "GET", headers }
);
}

/**
* Disable sippy on the bucket with the given name
*/
export async function deleteR2Sippy(
accountId: string,
bucketName: string,
jurisdiction?: string
): Promise<void> {
const headers: HeadersInit = {};
if (jurisdiction !== undefined) {
headers["cf-r2-jurisdiction"] = jurisdiction;
}
return await fetchResult(
`/accounts/${accountId}/r2/buckets/${bucketName}/sippy`,
{ method: "DELETE", headers }
);
}

/**
* Enable sippy on the bucket with the given name
*/
export async function putR2Sippy(
accountId: string,
bucketName: string,
config: {
provider: "AWS";
zone: string | undefined;
bucket: string;
key_id: string;
access_key: string;
r2_key_id: string;
r2_access_key: string;
},
jurisdiction?: string
): Promise<void> {
const headers: HeadersInit = {};
if (jurisdiction !== undefined) {
headers["cf-r2-jurisdiction"] = jurisdiction;
}
return await fetchResult(
`/accounts/${accountId}/r2/buckets/${bucketName}/sippy`,
{ method: "PUT", body: JSON.stringify(config), headers }
);
}
136 changes: 136 additions & 0 deletions packages/wrangler/src/r2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ import {
createR2Bucket,
deleteR2Bucket,
deleteR2Object,
deleteR2Sippy,
getR2Object,
getR2Sippy,
listR2Buckets,
putR2Object,
putR2Sippy,
usingLocalBucket,
} from "./helpers";

Expand Down Expand Up @@ -503,6 +506,139 @@ export function r2(r2Yargs: CommonYargsArgv) {
});
}
);

r2BucketYargs.command(
"sippy",
"Manage Sippy incremental migration on an R2 bucket",
(sippyYargs) => {
return sippyYargs
.command(
"enable <name>",
"Enable Sippy on an R2 bucket",
(yargs) =>
yargs
.positional("name", {
describe: "The name of the bucket",
type: "string",
demandOption: true,
})
.option("jurisdiction", {
describe: "The jurisdiction where the bucket exists",
alias: "J",
requiresArg: true,
type: "string",
})
.option("provider", {
choices: ["AWS"],
default: "AWS",
implies: [
"bucket",
"key-id",
"secret-access-key",
"r2-key-id",
"r2-secret-access-key",
],
})
.option("bucket", {
description: "The name of the upstream bucket",
string: true,
})
.option("region", {
description: "The region of the upstream bucket",
string: true,
})
.option("key-id", {
description:
"The secret access key id for the upstream bucket",
string: true,
})
.option("secret-access-key", {
description:
"The secret access key for the upstream bucket",
string: true,
})
.option("r2-key-id", {
description: "The secret access key id for this R2 bucket",
string: true,
})
.option("r2-secret-access-key", {
description: "The secret access key for this R2 bucket",
string: true,
}),

async (args) => {
const config = readConfig(args.config, args);
const accountId = await requireAuth(config);

await putR2Sippy(
accountId,
args.name,
{
provider: "AWS",
zone: args["region"],
bucket: args.bucket ?? "",
key_id: args["key-id"] ?? "",
access_key: args["secret-access-key"] ?? "",
r2_key_id: args["r2-key-id"] ?? "",
r2_access_key: args["r2-secret-access-key"] ?? "",
},
args.jurisdiction
);
}
)
.command(
"disable <name>",
"Disable Sippy on an R2 bucket",
(yargs) =>
yargs
.positional("name", {
describe: "The name of the bucket",
type: "string",
demandOption: true,
})
.option("jurisdiction", {
describe: "The jurisdiction where the bucket exists",
alias: "J",
requiresArg: true,
type: "string",
}),
async (args) => {
const config = readConfig(args.config, args);
const accountId = await requireAuth(config);

await deleteR2Sippy(accountId, args.name, args.jurisdiction);
}
)
.command(
"get <name>",
"Check the status of Sippy on an R2 bucket",
(yargs) =>
yargs
.positional("name", {
describe: "The name of the bucket",
type: "string",
demandOption: true,
})
.option("jurisdiction", {
describe: "The jurisdiction where the bucket exists",
alias: "J",
requiresArg: true,
type: "string",
}),
async (args) => {
const config = readConfig(args.config, args);
const accountId = await requireAuth(config);

const sippyBucket = await getR2Sippy(
accountId,
args.name,
args.jurisdiction
);
logger.log(`Sippy upstream bucket: ${sippyBucket}.`);
}
);
}
);
return r2BucketYargs;
});
}

0 comments on commit e8a2a1d

Please sign in to comment.