github.com/terraform-modules-krish/terratest@v0.29.0/modules/aws/s3.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "strings" 6 7 "github.com/aws/aws-sdk-go/aws" 8 "github.com/aws/aws-sdk-go/service/s3" 9 "github.com/aws/aws-sdk-go/service/s3/s3manager" 10 "github.com/terraform-modules-krish/terratest/modules/logger" 11 "github.com/terraform-modules-krish/terratest/modules/testing" 12 "github.com/stretchr/testify/require" 13 ) 14 15 // FindS3BucketWithTag finds the name of the S3 bucket in the given region with the given tag key=value. 16 func FindS3BucketWithTag(t testing.TestingT, awsRegion string, key string, value string) string { 17 bucket, err := FindS3BucketWithTagE(t, awsRegion, key, value) 18 require.NoError(t, err) 19 20 return bucket 21 } 22 23 // FindS3BucketWithTagE finds the name of the S3 bucket in the given region with the given tag key=value. 24 func FindS3BucketWithTagE(t testing.TestingT, awsRegion string, key string, value string) (string, error) { 25 s3Client, err := NewS3ClientE(t, awsRegion) 26 if err != nil { 27 return "", err 28 } 29 30 resp, err := s3Client.ListBuckets(&s3.ListBucketsInput{}) 31 if err != nil { 32 return "", err 33 } 34 35 for _, bucket := range resp.Buckets { 36 tagResponse, err := s3Client.GetBucketTagging(&s3.GetBucketTaggingInput{Bucket: bucket.Name}) 37 38 if err != nil { 39 if !strings.Contains(err.Error(), "AuthorizationHeaderMalformed") && 40 !strings.Contains(err.Error(), "BucketRegionError") && 41 !strings.Contains(err.Error(), "NoSuchTagSet") { 42 return "", err 43 } 44 } 45 46 for _, tag := range tagResponse.TagSet { 47 if *tag.Key == key && *tag.Value == value { 48 logger.Logf(t, "Found S3 bucket %s with tag %s=%s", *bucket.Name, key, value) 49 return *bucket.Name, nil 50 } 51 } 52 } 53 54 return "", nil 55 } 56 57 // GetS3ObjectContents fetches the contents of the object in the given bucket with the given key and return it as a string. 58 func GetS3ObjectContents(t testing.TestingT, awsRegion string, bucket string, key string) string { 59 contents, err := GetS3ObjectContentsE(t, awsRegion, bucket, key) 60 require.NoError(t, err) 61 62 return contents 63 } 64 65 // GetS3ObjectContentsE fetches the contents of the object in the given bucket with the given key and return it as a string. 66 func GetS3ObjectContentsE(t testing.TestingT, awsRegion string, bucket string, key string) (string, error) { 67 s3Client, err := NewS3ClientE(t, awsRegion) 68 if err != nil { 69 return "", err 70 } 71 72 res, err := s3Client.GetObject(&s3.GetObjectInput{ 73 Bucket: &bucket, 74 Key: &key, 75 }) 76 77 if err != nil { 78 return "", err 79 } 80 81 buf := new(bytes.Buffer) 82 _, err = buf.ReadFrom(res.Body) 83 if err != nil { 84 return "", err 85 } 86 87 contents := buf.String() 88 logger.Logf(t, "Read contents from s3://%s/%s", bucket, key) 89 90 return contents, nil 91 } 92 93 // CreateS3Bucket creates an S3 bucket in the given region with the given name. Note that S3 bucket names must be globally unique. 94 func CreateS3Bucket(t testing.TestingT, region string, name string) { 95 err := CreateS3BucketE(t, region, name) 96 require.NoError(t, err) 97 } 98 99 // CreateS3BucketE creates an S3 bucket in the given region with the given name. Note that S3 bucket names must be globally unique. 100 func CreateS3BucketE(t testing.TestingT, region string, name string) error { 101 logger.Logf(t, "Creating bucket %s in %s", name, region) 102 103 s3Client, err := NewS3ClientE(t, region) 104 if err != nil { 105 return err 106 } 107 108 params := &s3.CreateBucketInput{ 109 Bucket: aws.String(name), 110 } 111 _, err = s3Client.CreateBucket(params) 112 return err 113 } 114 115 // PutS3BucketPolicy applies an IAM resource policy to a given S3 bucket to create it's bucket policy 116 func PutS3BucketPolicy(t testing.TestingT, region string, bucketName string, policyJSONString string) { 117 err := PutS3BucketPolicyE(t, region, bucketName, policyJSONString) 118 require.NoError(t, err) 119 } 120 121 // PutS3BucketPolicyE applies an IAM resource policy to a given S3 bucket to create it's bucket policy 122 func PutS3BucketPolicyE(t testing.TestingT, region string, bucketName string, policyJSONString string) error { 123 logger.Logf(t, "Applying bucket policy for bucket %s in %s", bucketName, region) 124 125 s3Client, err := NewS3ClientE(t, region) 126 if err != nil { 127 return err 128 } 129 130 input := &s3.PutBucketPolicyInput{ 131 Bucket: aws.String(bucketName), 132 Policy: aws.String(policyJSONString), 133 } 134 135 _, err = s3Client.PutBucketPolicy(input) 136 return err 137 } 138 139 // PutS3BucketVersioning creates an S3 bucket versioning configuration in the given region against the given bucket name, WITHOUT requiring MFA to remove versioning. 140 func PutS3BucketVersioning(t testing.TestingT, region string, bucketName string) { 141 err := PutS3BucketVersioningE(t, region, bucketName) 142 require.NoError(t, err) 143 } 144 145 // PutS3BucketVersioningE creates an S3 bucket versioning configuration in the given region against the given bucket name, WITHOUT requiring MFA to remove versioning. 146 func PutS3BucketVersioningE(t testing.TestingT, region string, bucketName string) error { 147 logger.Logf(t, "Creating bucket versioning configuration for bucket %s in %s", bucketName, region) 148 149 s3Client, err := NewS3ClientE(t, region) 150 if err != nil { 151 return err 152 } 153 154 input := &s3.PutBucketVersioningInput{ 155 Bucket: aws.String(bucketName), 156 VersioningConfiguration: &s3.VersioningConfiguration{ 157 MFADelete: aws.String("Disabled"), 158 Status: aws.String("Enabled"), 159 }, 160 } 161 162 _, err = s3Client.PutBucketVersioning(input) 163 return err 164 } 165 166 // DeleteS3Bucket destroys the S3 bucket in the given region with the given name. 167 func DeleteS3Bucket(t testing.TestingT, region string, name string) { 168 err := DeleteS3BucketE(t, region, name) 169 require.NoError(t, err) 170 } 171 172 // DeleteS3BucketE destroys the S3 bucket in the given region with the given name. 173 func DeleteS3BucketE(t testing.TestingT, region string, name string) error { 174 logger.Logf(t, "Deleting bucket %s in %s", region, name) 175 176 s3Client, err := NewS3ClientE(t, region) 177 if err != nil { 178 return err 179 } 180 181 params := &s3.DeleteBucketInput{ 182 Bucket: aws.String(name), 183 } 184 _, err = s3Client.DeleteBucket(params) 185 return err 186 } 187 188 // EmptyS3Bucket removes the contents of an S3 bucket in the given region with the given name. 189 func EmptyS3Bucket(t testing.TestingT, region string, name string) { 190 err := EmptyS3BucketE(t, region, name) 191 require.NoError(t, err) 192 } 193 194 // EmptyS3BucketE removes the contents of an S3 bucket in the given region with the given name. 195 func EmptyS3BucketE(t testing.TestingT, region string, name string) error { 196 logger.Logf(t, "Emptying bucket %s in %s", name, region) 197 198 s3Client, err := NewS3ClientE(t, region) 199 if err != nil { 200 return err 201 } 202 203 params := &s3.ListObjectVersionsInput{ 204 Bucket: aws.String(name), 205 } 206 207 for { 208 // Requesting a batch of objects from s3 bucket 209 bucketObjects, err := s3Client.ListObjectVersions(params) 210 if err != nil { 211 return err 212 } 213 214 //Checks if the bucket is already empty 215 if len((*bucketObjects).Versions) == 0 { 216 logger.Logf(t, "Bucket %s is already empty", name) 217 return nil 218 } 219 220 //creating an array of pointers of ObjectIdentifier 221 objectsToDelete := make([]*s3.ObjectIdentifier, 0, 1000) 222 for _, object := range (*bucketObjects).Versions { 223 obj := s3.ObjectIdentifier{ 224 Key: object.Key, 225 VersionId: object.VersionId, 226 } 227 objectsToDelete = append(objectsToDelete, &obj) 228 } 229 230 for _, object := range (*bucketObjects).DeleteMarkers { 231 obj := s3.ObjectIdentifier{ 232 Key: object.Key, 233 VersionId: object.VersionId, 234 } 235 objectsToDelete = append(objectsToDelete, &obj) 236 } 237 238 //Creating JSON payload for bulk delete 239 deleteArray := s3.Delete{Objects: objectsToDelete} 240 deleteParams := &s3.DeleteObjectsInput{ 241 Bucket: aws.String(name), 242 Delete: &deleteArray, 243 } 244 245 //Running the Bulk delete job (limit 1000) 246 _, err = s3Client.DeleteObjects(deleteParams) 247 if err != nil { 248 return err 249 } 250 251 if *(*bucketObjects).IsTruncated { //if there are more objects in the bucket, IsTruncated = true 252 // params.Marker = (*deleteParams).Delete.Objects[len((*deleteParams).Delete.Objects)-1].Key 253 params.KeyMarker = bucketObjects.NextKeyMarker 254 logger.Logf(t, "Requesting next batch | %s", *(params.KeyMarker)) 255 } else { //if all objects in the bucket have been cleaned up. 256 break 257 } 258 } 259 logger.Logf(t, "Bucket %s is now empty", name) 260 return err 261 } 262 263 // GetS3BucketVersioning fetches the given bucket's versioning configuration status and returns it as a string 264 func GetS3BucketVersioning(t testing.TestingT, awsRegion string, bucket string) string { 265 versioningStatus, err := GetS3BucketVersioningE(t, awsRegion, bucket) 266 require.NoError(t, err) 267 268 return versioningStatus 269 } 270 271 // GetS3BucketVersioningE fetches the given bucket's versioning configuration status and returns it as a string 272 func GetS3BucketVersioningE(t testing.TestingT, awsRegion string, bucket string) (string, error) { 273 s3Client, err := NewS3ClientE(t, awsRegion) 274 if err != nil { 275 return "", err 276 } 277 278 res, err := s3Client.GetBucketVersioning(&s3.GetBucketVersioningInput{ 279 Bucket: &bucket, 280 }) 281 if err != nil { 282 return "", err 283 } 284 285 return aws.StringValue(res.Status), nil 286 } 287 288 // GetS3BucketPolicy fetches the given bucket's resource policy and returns it as a string 289 func GetS3BucketPolicy(t testing.TestingT, awsRegion string, bucket string) string { 290 bucketPolicy, err := GetS3BucketPolicyE(t, awsRegion, bucket) 291 require.NoError(t, err) 292 293 return bucketPolicy 294 } 295 296 // GetS3BucketPolicyE fetches the given bucket's resource policy and returns it as a string 297 func GetS3BucketPolicyE(t testing.TestingT, awsRegion string, bucket string) (string, error) { 298 s3Client, err := NewS3ClientE(t, awsRegion) 299 if err != nil { 300 return "", err 301 } 302 303 res, err := s3Client.GetBucketPolicy(&s3.GetBucketPolicyInput{ 304 Bucket: &bucket, 305 }) 306 if err != nil { 307 return "", err 308 } 309 310 return aws.StringValue(res.Policy), nil 311 } 312 313 // AssertS3BucketExists checks if the given S3 bucket exists in the given region and fail the test if it does not. 314 func AssertS3BucketExists(t testing.TestingT, region string, name string) { 315 err := AssertS3BucketExistsE(t, region, name) 316 require.NoError(t, err) 317 } 318 319 // AssertS3BucketExistsE checks if the given S3 bucket exists in the given region and return an error if it does not. 320 func AssertS3BucketExistsE(t testing.TestingT, region string, name string) error { 321 s3Client, err := NewS3ClientE(t, region) 322 if err != nil { 323 return err 324 } 325 326 params := &s3.HeadBucketInput{ 327 Bucket: aws.String(name), 328 } 329 _, err = s3Client.HeadBucket(params) 330 return err 331 } 332 333 // AssertS3BucketVersioningExists checks if the given S3 bucket has a versioning configuration enabled and returns an error if it does not. 334 func AssertS3BucketVersioningExists(t testing.TestingT, region string, bucketName string) { 335 err := AssertS3BucketVersioningExistsE(t, region, bucketName) 336 require.NoError(t, err) 337 } 338 339 // AssertS3BucketVersioningExistsE checks if the given S3 bucket has a versioning configuration enabled and returns an error if it does not. 340 func AssertS3BucketVersioningExistsE(t testing.TestingT, region string, bucketName string) error { 341 status, err := GetS3BucketVersioningE(t, region, bucketName) 342 if err != nil { 343 return err 344 } 345 346 if status == "Enabled" { 347 return nil 348 } 349 return NewBucketVersioningNotEnabledError(bucketName, region, status) 350 } 351 352 // AssertS3BucketPolicyExists checks if the given S3 bucket has a resource policy attached and returns an error if it does not 353 func AssertS3BucketPolicyExists(t testing.TestingT, region string, bucketName string) { 354 err := AssertS3BucketPolicyExistsE(t, region, bucketName) 355 require.NoError(t, err) 356 } 357 358 // AssertS3BucketPolicyExistsE checks if the given S3 bucket has a resource policy attached and returns an error if it does not 359 func AssertS3BucketPolicyExistsE(t testing.TestingT, region string, bucketName string) error { 360 policy, err := GetS3BucketPolicyE(t, region, bucketName) 361 if err != nil { 362 return err 363 } 364 365 if policy == "" { 366 return NewNoBucketPolicyError(bucketName, region, policy) 367 } 368 return nil 369 } 370 371 // NewS3Client creates an S3 client. 372 func NewS3Client(t testing.TestingT, region string) *s3.S3 { 373 client, err := NewS3ClientE(t, region) 374 require.NoError(t, err) 375 376 return client 377 } 378 379 // NewS3ClientE creates an S3 client. 380 func NewS3ClientE(t testing.TestingT, region string) (*s3.S3, error) { 381 sess, err := NewAuthenticatedSession(region) 382 if err != nil { 383 return nil, err 384 } 385 386 return s3.New(sess), nil 387 } 388 389 // NewS3Uploader creates an S3 Uploader. 390 func NewS3Uploader(t testing.TestingT, region string) *s3manager.Uploader { 391 uploader, err := NewS3UploaderE(t, region) 392 require.NoError(t, err) 393 return uploader 394 } 395 396 // NewS3UploaderE creates an S3 Uploader. 397 func NewS3UploaderE(t testing.TestingT, region string) (*s3manager.Uploader, error) { 398 sess, err := NewAuthenticatedSession(region) 399 if err != nil { 400 return nil, err 401 } 402 403 return s3manager.NewUploader(sess), nil 404 }