Skip to content

Commit 0439946

Browse files
authored
feat(s3-control): support S3 Outposts control plane (#1553)
* chore(s3-control): update s3 control model * feat(middleware-sdk-s3-control): add outpost-endpoints middleware * feat(client-s3-control): codegen client and remove host prefix customization Remove the host prefix customziation because with new S3 control model, the host prefix is modeled. So no customization is needed. * feat(middleware-sdk-s3-control): remove host prefix customization implementation * feat(middleware-sdk-s3-control): add outpost control plane customization * feat(client-s3-control): integrate outposts control plane customization * test(client-s3-control): add functional test * docs(middleware-sdk-s3-control): add more docs
1 parent 92e1fc4 commit 0439946

File tree

58 files changed

+7345
-1410
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+7345
-1410
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/// <reference types="mocha" />
2+
import { expect } from "chai";
3+
import { S3Control } from "./S3Control";
4+
import { FinalizeRequestMiddleware } from "@aws-sdk/types";
5+
6+
describe("S3Control Client", () => {
7+
// Middleware intercept request and return it before reaching the HTTP client. It records the request and context
8+
// and return them in the Metadata.
9+
const interceptionMiddleware: FinalizeRequestMiddleware<any, any> = (next, context) => (args) => {
10+
return Promise.resolve({ output: { $metadata: { request: args.request } }, response: "" as any });
11+
};
12+
const region = "us-east-1";
13+
const credentials = { accessKeyId: "AKID", secretAccessKey: "SECRET" };
14+
const s3Control = new S3Control({ region, credentials });
15+
s3Control.middlewareStack.add(interceptionMiddleware, { step: "finalizeRequest", name: "interceptionMiddleware" });
16+
const HEADER_OUTPOST_ID = "x-amz-outpost-id";
17+
const HEADER_ACCOUNT_ID = "x-amz-account-id";
18+
const dateStr = new Date().toISOString().substr(0, 10).replace(/[\-:]/g, "");
19+
20+
describe("CreateBucket", () => {
21+
it("should populate correct endpoint and signing region", async () => {
22+
const {
23+
// @ts-ignore request is set in $metadata by interception middleware.
24+
$metadata: { request },
25+
} = await s3Control.createBucket({ Bucket: "Bucket" });
26+
expect(request.hostname).eql(`s3-control.${region}.amazonaws.com`);
27+
expect(request.headers["authorization"]).contains(
28+
`Credential=${credentials.accessKeyId}/${dateStr}/${region}/s3/aws4_request`
29+
);
30+
});
31+
32+
it("should populate correct endpoint and signing region if OutpostId is supplied", async () => {
33+
const OutpostId = "123456789012";
34+
const {
35+
// @ts-ignore request is set in $metadata by interception middleware.
36+
$metadata: { request },
37+
} = await s3Control.createBucket({ Bucket: "Bucket", OutpostId });
38+
expect(request.hostname).eql(`s3-outposts.${region}.amazonaws.com`);
39+
expect(request.headers[HEADER_OUTPOST_ID]).eql(OutpostId);
40+
expect(request.headers["authorization"]).contains(
41+
`Credential=${credentials.accessKeyId}/${dateStr}/${region}/s3-outposts/aws4_request`
42+
);
43+
});
44+
});
45+
46+
describe("ListRegionalBuckets", () => {
47+
const AccountId = "123456789012";
48+
it("should populate correct endpoint and signing region", async () => {
49+
const {
50+
// @ts-ignore request is set in $metadata by interception middleware.
51+
$metadata: { request },
52+
} = await s3Control.listRegionalBuckets({ AccountId });
53+
expect(request.hostname).eql(`${AccountId}.s3-control.${region}.amazonaws.com`);
54+
expect(request.headers["authorization"]).contains(
55+
`Credential=${credentials.accessKeyId}/${dateStr}/${region}/s3/aws4_request`
56+
);
57+
});
58+
59+
it("should populate correct endpoint and signing region if OutpostId is supplied", async () => {
60+
const OutpostId = "123456789012";
61+
const {
62+
// @ts-ignore request is set in $metadata by interception middleware.
63+
$metadata: { request },
64+
} = await s3Control.listRegionalBuckets({ AccountId, OutpostId });
65+
expect(request.hostname).eql(`s3-outposts.${region}.amazonaws.com`);
66+
expect(request.headers[HEADER_OUTPOST_ID]).eql(OutpostId);
67+
expect(request.headers[HEADER_ACCOUNT_ID]).eql(AccountId);
68+
expect(request.headers["authorization"]).contains(
69+
`Credential=${credentials.accessKeyId}/${dateStr}/${region}/s3-outposts/aws4_request`
70+
);
71+
});
72+
});
73+
74+
// Use GetAccessPointCommand to validate the customizations for Access Point ARN customizations
75+
describe("Outposts Access Point ARN", () => {
76+
const AccountId = "123456789012";
77+
const OutpostId = "op-01234567890123456";
78+
const accesspointArn = `arn:aws:s3-outposts:${region}:${AccountId}:outpost:${OutpostId}:accesspoint:myaccesspoint`;
79+
it("should populate correct endpoint if Access Point name is non-ARN", async () => {
80+
const {
81+
// @ts-ignore request is set in $metadata by interception middleware.
82+
$metadata: { request },
83+
} = await s3Control.getAccessPoint({ Name: "FakeAccessPoint", AccountId });
84+
expect(request.hostname).eql(`${AccountId}.s3-control.${region}.amazonaws.com`);
85+
expect(request.headers["authorization"]).contains(
86+
`Credential=${credentials.accessKeyId}/${dateStr}/${region}/s3/aws4_request`
87+
);
88+
});
89+
90+
it("should populate correct endpoint and signing region if Access Point name is ARN", async () => {
91+
const {
92+
// @ts-ignore request is set in $metadata by interception middleware.
93+
$metadata: { request },
94+
} = await s3Control.getAccessPoint({ Name: accesspointArn });
95+
expect(request.hostname).eql(`s3-outposts.${region}.amazonaws.com`);
96+
expect(request.headers[HEADER_OUTPOST_ID]).eql(OutpostId);
97+
expect(request.headers[HEADER_ACCOUNT_ID]).eql(AccountId);
98+
expect(request.headers["authorization"]).contains(
99+
`Credential=${credentials.accessKeyId}/${dateStr}/${region}/s3-outposts/aws4_request`
100+
);
101+
});
102+
});
103+
104+
// Use GetBucketCommand to validate the customizations for Bucket ARN customizations
105+
describe("Outposts Bucket ARN", () => {
106+
const AccountId = "123456789012";
107+
const OutpostId = "op-01234567890123456";
108+
const bucketArn = `arn:aws:s3-outposts:${region}:${AccountId}:outpost/${OutpostId}/bucket/bucket-id"`;
109+
it("should populate correct endpoint if Bucket name is non-ARN", async () => {
110+
const {
111+
// @ts-ignore request is set in $metadata by interception middleware.
112+
$metadata: { request },
113+
} = await s3Control.getBucket({ Bucket: "BucketName", AccountId });
114+
expect(request.hostname).eql(`${AccountId}.s3-control.${region}.amazonaws.com`);
115+
expect(request.headers["authorization"]).contains(
116+
`Credential=${credentials.accessKeyId}/${dateStr}/${region}/s3/aws4_request`
117+
);
118+
});
119+
120+
it("should populate correct endpoint and signing region if Bucket name is ARN", async () => {
121+
const {
122+
// @ts-ignore request is set in $metadata by interception middleware.
123+
$metadata: { request },
124+
} = await s3Control.getBucket({ Bucket: bucketArn });
125+
expect(request.hostname).eql(`s3-outposts.${region}.amazonaws.com`);
126+
expect(request.headers[HEADER_OUTPOST_ID]).eql(OutpostId);
127+
expect(request.headers[HEADER_ACCOUNT_ID]).eql(AccountId);
128+
expect(request.headers["authorization"]).contains(
129+
`Credential=${credentials.accessKeyId}/${dateStr}/${region}/s3-outposts/aws4_request`
130+
);
131+
});
132+
});
133+
});

0 commit comments

Comments
 (0)