@@ -12,8 +12,15 @@ import {
1212 PutObjectRetentionCommand ,
1313 ObjectLockLegalHoldStatus ,
1414 ObjectLockRetentionMode ,
15+ GetBucketVersioningCommand ,
16+ BucketAlreadyExists ,
17+ BucketAlreadyOwnedByYou ,
18+ S3ServiceException ,
19+ waitUntilBucketExists ,
1520} from "@aws-sdk/client-s3" ;
1621
22+ import { retry } from "@aws-doc-sdk-examples/lib/utils/util-timers.js" ;
23+
1724/**
1825 * @typedef {import("@aws-doc-sdk-examples/lib/scenario/index.js") } Scenarios
1926 */
@@ -22,19 +29,26 @@ import {
2229 * @typedef {import("@aws-sdk/client-s3").S3Client } S3Client
2330 */
2431
25- const bucketPrefix = "js-object-locking" ;
32+ /**
33+ * @param {Scenarios } scenarios
34+ */
35+ const getBucketPrefix = ( scenarios ) =>
36+ new scenarios . ScenarioInput (
37+ "bucketPrefix" ,
38+ "Provide a prefix that will be used for bucket creation." ,
39+ { type : "input" , default : "amzn-s3-demo-bucket" } ,
40+ ) ;
2641
2742/**
2843 * @param {Scenarios } scenarios
29- * @param {S3Client } client
3044 */
3145const createBuckets = ( scenarios ) =>
3246 new scenarios . ScenarioOutput (
3347 "createBuckets" ,
34- `The following buckets will be created:
35- ${ bucketPrefix } -no-lock with object lock False.
36- ${ bucketPrefix } -lock-enabled with object lock True.
37- ${ bucketPrefix } -retention-after-creation with object lock False.` ,
48+ ( state ) => `The following buckets will be created:
49+ ${ state . bucketPrefix } -no-lock with object lock False.
50+ ${ state . bucketPrefix } -lock-enabled with object lock True.
51+ ${ state . bucketPrefix } -retention-after-creation with object lock False.` ,
3852 { preformatted : true } ,
3953 ) ;
4054
@@ -52,22 +66,42 @@ const confirmCreateBuckets = (scenarios) =>
5266 */
5367const createBucketsAction = ( scenarios , client ) =>
5468 new scenarios . ScenarioAction ( "createBucketsAction" , async ( state ) => {
55- const noLockBucketName = `${ bucketPrefix } -no-lock` ;
56- const lockEnabledBucketName = `${ bucketPrefix } -lock-enabled` ;
57- const retentionBucketName = `${ bucketPrefix } -retention-after-creation` ;
69+ const noLockBucketName = `${ state . bucketPrefix } -no-lock` ;
70+ const lockEnabledBucketName = `${ state . bucketPrefix } -lock-enabled` ;
71+ const retentionBucketName = `${ state . bucketPrefix } -retention-after-creation` ;
5872
59- await client . send ( new CreateBucketCommand ( { Bucket : noLockBucketName } ) ) ;
60- await client . send (
61- new CreateBucketCommand ( {
62- Bucket : lockEnabledBucketName ,
63- ObjectLockEnabledForBucket : true ,
64- } ) ,
65- ) ;
66- await client . send ( new CreateBucketCommand ( { Bucket : retentionBucketName } ) ) ;
73+ try {
74+ await client . send ( new CreateBucketCommand ( { Bucket : noLockBucketName } ) ) ;
75+ await waitUntilBucketExists ( { client } , { Bucket : noLockBucketName } ) ;
76+ await client . send (
77+ new CreateBucketCommand ( {
78+ Bucket : lockEnabledBucketName ,
79+ ObjectLockEnabledForBucket : true ,
80+ } ) ,
81+ ) ;
82+ await waitUntilBucketExists (
83+ { client } ,
84+ { Bucket : lockEnabledBucketName } ,
85+ ) ;
86+ await client . send (
87+ new CreateBucketCommand ( { Bucket : retentionBucketName } ) ,
88+ ) ;
89+ await waitUntilBucketExists ( { client } , { Bucket : retentionBucketName } ) ;
6790
68- state . noLockBucketName = noLockBucketName ;
69- state . lockEnabledBucketName = lockEnabledBucketName ;
70- state . retentionBucketName = retentionBucketName ;
91+ state . noLockBucketName = noLockBucketName ;
92+ state . lockEnabledBucketName = lockEnabledBucketName ;
93+ state . retentionBucketName = retentionBucketName ;
94+ } catch ( caught ) {
95+ if (
96+ caught instanceof BucketAlreadyExists ||
97+ caught instanceof BucketAlreadyOwnedByYou
98+ ) {
99+ console . error ( `${ caught . name } : ${ caught . message } ` ) ;
100+ state . earlyExit = true ;
101+ } else {
102+ throw caught ;
103+ }
104+ }
71105 } ) ;
72106
73107/**
@@ -76,13 +110,13 @@ const createBucketsAction = (scenarios, client) =>
76110const populateBuckets = ( scenarios ) =>
77111 new scenarios . ScenarioOutput (
78112 "populateBuckets" ,
79- `The following test files will be created:
80- file0.txt in ${ bucketPrefix } -no-lock.
81- file1.txt in ${ bucketPrefix } -no-lock.
82- file0.txt in ${ bucketPrefix } -lock-enabled.
83- file1.txt in ${ bucketPrefix } -lock-enabled.
84- file0.txt in ${ bucketPrefix } -retention-after-creation.
85- file1.txt in ${ bucketPrefix } -retention-after-creation.` ,
113+ ( state ) => `The following test files will be created:
114+ file0.txt in ${ state . bucketPrefix } -no-lock.
115+ file1.txt in ${ state . bucketPrefix } -no-lock.
116+ file0.txt in ${ state . bucketPrefix } -lock-enabled.
117+ file1.txt in ${ state . bucketPrefix } -lock-enabled.
118+ file0.txt in ${ state . bucketPrefix } -retention-after-creation.
119+ file1.txt in ${ state . bucketPrefix } -retention-after-creation.` ,
86120 { preformatted : true } ,
87121 ) ;
88122
@@ -102,54 +136,64 @@ const confirmPopulateBuckets = (scenarios) =>
102136 */
103137const populateBucketsAction = ( scenarios , client ) =>
104138 new scenarios . ScenarioAction ( "populateBucketsAction" , async ( state ) => {
105- await client . send (
106- new PutObjectCommand ( {
107- Bucket : state . noLockBucketName ,
108- Key : "file0.txt" ,
109- Body : "Content" ,
110- ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
111- } ) ,
112- ) ;
113- await client . send (
114- new PutObjectCommand ( {
115- Bucket : state . noLockBucketName ,
116- Key : "file1.txt" ,
117- Body : "Content" ,
118- ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
119- } ) ,
120- ) ;
121- await client . send (
122- new PutObjectCommand ( {
123- Bucket : state . lockEnabledBucketName ,
124- Key : "file0.txt" ,
125- Body : "Content" ,
126- ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
127- } ) ,
128- ) ;
129- await client . send (
130- new PutObjectCommand ( {
131- Bucket : state . lockEnabledBucketName ,
132- Key : "file1.txt" ,
133- Body : "Content" ,
134- ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
135- } ) ,
136- ) ;
137- await client . send (
138- new PutObjectCommand ( {
139- Bucket : state . retentionBucketName ,
140- Key : "file0.txt" ,
141- Body : "Content" ,
142- ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
143- } ) ,
144- ) ;
145- await client . send (
146- new PutObjectCommand ( {
147- Bucket : state . retentionBucketName ,
148- Key : "file1.txt" ,
149- Body : "Content" ,
150- ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
151- } ) ,
152- ) ;
139+ try {
140+ await client . send (
141+ new PutObjectCommand ( {
142+ Bucket : state . noLockBucketName ,
143+ Key : "file0.txt" ,
144+ Body : "Content" ,
145+ ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
146+ } ) ,
147+ ) ;
148+ await client . send (
149+ new PutObjectCommand ( {
150+ Bucket : state . noLockBucketName ,
151+ Key : "file1.txt" ,
152+ Body : "Content" ,
153+ ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
154+ } ) ,
155+ ) ;
156+ await client . send (
157+ new PutObjectCommand ( {
158+ Bucket : state . lockEnabledBucketName ,
159+ Key : "file0.txt" ,
160+ Body : "Content" ,
161+ ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
162+ } ) ,
163+ ) ;
164+ await client . send (
165+ new PutObjectCommand ( {
166+ Bucket : state . lockEnabledBucketName ,
167+ Key : "file1.txt" ,
168+ Body : "Content" ,
169+ ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
170+ } ) ,
171+ ) ;
172+ await client . send (
173+ new PutObjectCommand ( {
174+ Bucket : state . retentionBucketName ,
175+ Key : "file0.txt" ,
176+ Body : "Content" ,
177+ ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
178+ } ) ,
179+ ) ;
180+ await client . send (
181+ new PutObjectCommand ( {
182+ Bucket : state . retentionBucketName ,
183+ Key : "file1.txt" ,
184+ Body : "Content" ,
185+ ChecksumAlgorithm : ChecksumAlgorithm . SHA256 ,
186+ } ) ,
187+ ) ;
188+ } catch ( caught ) {
189+ if ( caught instanceof S3ServiceException ) {
190+ console . error (
191+ `Error from S3 while uploading object. ${ caught . name } : ${ caught . message } ` ,
192+ ) ;
193+ } else {
194+ throw caught ;
195+ }
196+ }
153197 } ) ;
154198
155199/**
@@ -158,8 +202,10 @@ const populateBucketsAction = (scenarios, client) =>
158202const updateRetention = ( scenarios ) =>
159203 new scenarios . ScenarioOutput (
160204 "updateRetention" ,
161- `A bucket can be configured to use object locking with a default retention period.
162- A default retention period will be configured for ${ bucketPrefix } -retention-after-creation.` ,
205+ (
206+ state ,
207+ ) => `A bucket can be configured to use object locking with a default retention period.
208+ A default retention period will be configured for ${ state . bucketPrefix } -retention-after-creation.` ,
163209 { preformatted : true } ,
164210 ) ;
165211
@@ -189,6 +235,17 @@ const updateRetentionAction = (scenarios, client) =>
189235 } ) ,
190236 ) ;
191237
238+ const getBucketVersioning = new GetBucketVersioningCommand ( {
239+ Bucket : state . retentionBucketName ,
240+ } ) ;
241+
242+ await retry ( { intervalInMs : 500 , maxRetries : 10 } , async ( ) => {
243+ const { Status } = await client . send ( getBucketVersioning ) ;
244+ if ( Status !== "Enabled" ) {
245+ throw new Error ( `Bucket versioning is not enabled.` ) ;
246+ }
247+ } ) ;
248+
192249 await client . send (
193250 new PutObjectLockConfigurationCommand ( {
194251 Bucket : state . retentionBucketName ,
@@ -211,8 +268,8 @@ const updateRetentionAction = (scenarios, client) =>
211268const updateLockPolicy = ( scenarios ) =>
212269 new scenarios . ScenarioOutput (
213270 "updateLockPolicy" ,
214- `Object lock policies can also be added to existing buckets.
215- An object lock policy will be added to ${ bucketPrefix } -lock-enabled.`,
271+ ( state ) => `Object lock policies can also be added to existing buckets.
272+ An object lock policy will be added to ${ state . bucketPrefix } -lock-enabled.` ,
216273 { preformatted : true } ,
217274 ) ;
218275
@@ -403,6 +460,7 @@ const setRetentionPeriodFileRetentionAction = (scenarios, client) =>
403460 ) ;
404461
405462export {
463+ getBucketPrefix ,
406464 createBuckets ,
407465 confirmCreateBuckets ,
408466 createBucketsAction ,
0 commit comments