s3_upload.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. # ----------------------------------------------------------------------------------
  2. # Imports
  3. # ----------------------------------------------------------------------------------
  4. import boto3
  5. from boto3.s3.transfer import TransferConfig
  6. from botocore.exceptions import NoCredentialsError
  7. import coloredlogs
  8. import configparser
  9. import logging
  10. import os
  11. import sys
  12. import threading
  13. # ----------------------------------------------------------------------------------
  14. # Types
  15. # ----------------------------------------------------------------------------------
  16. class S3Api:
  17. def __init__(self):
  18. # Configuration
  19. config = configparser.ConfigParser()
  20. path_to_config = os.path.dirname(os.path.realpath(__file__))
  21. config.read(os.path.join(path_to_config, 'config.ini'))
  22. self.uploads = dict()
  23. parse_config = True
  24. index = 0
  25. while parse_config:
  26. bucket_key = 'bucket{}'.format(index)
  27. file_key = 'files{}'.format(index)
  28. if bucket_key in config['Uploads'] and file_key in config['Uploads']:
  29. self.uploads[config['Uploads'][bucket_key]] = config['Uploads'][file_key]
  30. else:
  31. parse_config = False
  32. index += 1
  33. # Grab keys
  34. self._access_key = config['AWS']['access']
  35. self._secret_key = config['AWS']['secret']
  36. # Initialize client
  37. self.s3 = boto3.client('s3',
  38. aws_access_key_id=self._access_key,
  39. aws_secret_access_key=self._secret_key)
  40. # Initialize resource
  41. self.s3_resource = boto3.resource('s3',
  42. aws_access_key_id=self._access_key,
  43. aws_secret_access_key=self._secret_key)
  44. # ------------------------------------------------------------------------------
  45. def upload_files(self):
  46. for bucket in self.uploads:
  47. files = [file.strip() for file in self.uploads[bucket].split(',')]
  48. for file in files:
  49. self._upload_file_to_s3(file, bucket)
  50. # ------------------------------------------------------------------------------
  51. def _upload_file_to_s3(self, local_file, bucket, s3_file=None):
  52. if not s3_file:
  53. s3_file = os.path.basename(local_file)
  54. if os.path.getsize(local_file) < 1073741824: # File size is less than a gig
  55. try:
  56. self.s3.upload_file(local_file, bucket, s3_file)
  57. logger.info("\nUploaded {} to S3".format(local_file))
  58. except FileNotFoundError:
  59. logger.error("\nThe file {} was not found".format(local_file))
  60. except NoCredentialsError:
  61. logger.error("\nCredentials not available")
  62. else:
  63. try:
  64. self._multipart_upload(local_file, bucket, s3_file)
  65. logger.info("\nUploaded {} to S3".format(local_file))
  66. except FileNotFoundError:
  67. logger.error("\nThe file {} was not found".format(local_file))
  68. except NoCredentialsError:
  69. logger.error("\nCredentials not available")
  70. # ------------------------------------------------------------------------------
  71. def _multipart_upload(self, local_file, bucket, s3_file):
  72. transfer_config = TransferConfig(multipart_threshold=1024 * 25,
  73. multipart_chunksize=1024 * 25,
  74. use_threads=False)
  75. self.s3_resource.Object(bucket, s3_file).upload_file(local_file,
  76. Config=transfer_config,
  77. Callback=ProgressPercentage(local_file))
  78. class ProgressPercentage(object):
  79. def __init__(self, filename):
  80. self._filename = filename
  81. self._size = float(os.path.getsize(filename))
  82. self._seen_so_far = 0
  83. self._lock = threading.Lock()
  84. def __call__(self, bytes_amount):
  85. # To simplify we'll assume this is hooked up
  86. # to a single filename.
  87. with self._lock:
  88. self._seen_so_far += bytes_amount
  89. percentage = (self._seen_so_far / self._size) * 100
  90. sys.stdout.write(
  91. "\r%s %s / %s (%.2f%%)" % (
  92. self._filename, self._seen_so_far, self._size,
  93. percentage))
  94. sys.stdout.flush()
  95. # ----------------------------------------------------------------------------------
  96. # Globals
  97. # ----------------------------------------------------------------------------------
  98. # Initialize logging
  99. coloredlogs.DEFAULT_LEVEL_STYLES['debug'] = {}
  100. coloredlogs.DEFAULT_LEVEL_STYLES['info'] = {'color': 'green'}
  101. logger = logging.getLogger(__name__)
  102. coloredlogs.install(level='INFO')
  103. # ----------------------------------------------------------------------------------
  104. # Functions
  105. # ----------------------------------------------------------------------------------
  106. # ----------------------------------------------------------------------------------
  107. # Main
  108. # ----------------------------------------------------------------------------------
  109. if __name__ == '__main__':
  110. api = S3Api()
  111. api.upload_files()