download_from_s3.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. '''
  9. Usage:
  10. Use EC2 role to download files to %WORKSPACE% folder from bucket bucket_name:
  11. python download_from_s3.py --base_dir %WORKSPACE% --files_to_download "file1,file2" --bucket bucket_name
  12. Use profile to download files to %WORKSPACE% folder from bucket bucket_name:
  13. python download_from_s3.py --base_dir %WORKSPACE% --profile profile --files_to_download "file1,file2" --bucket bucket_name
  14. '''
  15. import os
  16. import json
  17. import boto3
  18. from optparse import OptionParser
  19. from util import error
  20. def parse_args():
  21. parser = OptionParser()
  22. parser.add_option("--base_dir", dest="base_dir", default=os.getcwd(), help="Base directory to download files, If not given, then current directory is used.")
  23. parser.add_option("--files_to_download", dest="files_to_download", default=None, help="Files to download, separated by comma.")
  24. parser.add_option("--profile", dest="profile", default=None, help="The name of a profile to use. If not given, then the default profile is used.")
  25. parser.add_option("--bucket", dest="bucket", default=None, help="S3 bucket the files are downloaded from.")
  26. parser.add_option("--key_prefix", dest="key_prefix", default='', help="Object key prefix.")
  27. '''
  28. ExtraArgs used to call s3.download_file(), should be in json format. extra_args key must be one of: ACL, CacheControl, ContentDisposition, ContentEncoding, ContentLanguage, ContentType, Expires,
  29. GrantFullControl, GrantRead, GrantReadACP, GrantWriteACP, Metadata, RequestPayer, ServerSideEncryption, StorageClass,
  30. SSECustomerAlgorithm, SSECustomerKey, SSECustomerKeyMD5, SSEKMSKeyId, WebsiteRedirectLocation
  31. '''
  32. parser.add_option("--extra_args", dest="extra_args", default=None, help="Additional parameters used to download file.")
  33. parser.add_option("--max_retry", dest="max_retry", default=1, help="Maximum retry times to download file.")
  34. (options, args) = parser.parse_args()
  35. if not os.path.isdir(options.base_dir):
  36. error('{} is not a valid directory'.format(options.base_dir))
  37. if not options.files_to_download:
  38. error('Use --files_to_download to specify files to download, separated by comma.')
  39. if not options.bucket:
  40. error('Use --bucket to specify bucket that the files are downloaded from.')
  41. return options
  42. def get_client(service_name, profile_name=None):
  43. session = boto3.session.Session(profile_name=profile_name)
  44. client = session.client(service_name)
  45. return client
  46. def s3_download_file(client, base_dir, file, bucket, key_prefix=None, extra_args=None, max_retry=1):
  47. print('Downloading file {} from bucket {}.'.format(file, bucket))
  48. key = file if key_prefix is None else '{}/{}'.format(key_prefix, file)
  49. for x in range(max_retry):
  50. try:
  51. client.download_file(
  52. bucket, key, os.path.join(base_dir, file),
  53. ExtraArgs=extra_args
  54. )
  55. print('Download succeeded')
  56. return True
  57. except:
  58. print('Retrying download...')
  59. print('Download failed')
  60. return False
  61. def download_files(base_dir, files_to_download, bucket, key_prefix=None, profile=None, extra_args=None, max_retry=1):
  62. client = get_client('s3', profile)
  63. files_to_download = files_to_download.split(',')
  64. extra_args = json.loads(extra_args) if extra_args else None
  65. print('Downloading {} files from bucket {}.'.format(len(files_to_download), bucket))
  66. failure = []
  67. success = []
  68. for file in files_to_download:
  69. if not s3_download_file(client, base_dir, file, bucket, key_prefix, extra_args, max_retry):
  70. failure.append(file)
  71. else:
  72. success.append(file)
  73. print('{} files are downloaded successfully:'.format(len(success)))
  74. print('\n'.join(success))
  75. print('{} files failed to download:'.format(len(failure)))
  76. print('\n'.join(failure))
  77. # Exit with error code 1 if any file is failed to download
  78. if len(failure) > 0:
  79. return False
  80. return True
  81. if __name__ == "__main__":
  82. options = parse_args()
  83. download_files(options.base_dir, options.files_to_download, options.bucket, options.key_prefix, options.profile, options.extra_args, options.max_retry)