azure_tier.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #!/usr/bin/env python
  2. from azure_storage.methods import client_prep, create_blob_client, create_parent_parser, setup_arguments
  3. from argparse import ArgumentParser, RawTextHelpFormatter
  4. import coloredlogs
  5. import logging
  6. import azure
  7. import sys
  8. import os
  9. class AzureContainerTier(object):
  10. def main(self):
  11. self.container_name, self.connect_str, self.blob_service_client, self.container_client = \
  12. client_prep(container_name=self.container_name,
  13. passphrase=self.passphrase,
  14. account_name=self.account_name,
  15. create=False)
  16. self.container_tier(container_client=self.container_client,
  17. blob_service_client=self.blob_service_client,
  18. container_name=self.container_name,
  19. storage_tier=self.storage_tier)
  20. @staticmethod
  21. def container_tier(container_client, blob_service_client, container_name, storage_tier):
  22. """
  23. Set the storage tier for the specified container in Azure storage
  24. :param container_client: type azure.storage.blob.BlobServiceClient.ContainerClient
  25. :param blob_service_client: type: azure.storage.blob.BlobServiceClient
  26. :param container_name: type str: Name of the container of interest
  27. :param storage_tier: type str: Storage tier to use for the container
  28. """
  29. # Create a generator containing all the blobs in the container
  30. generator = container_client.list_blobs()
  31. try:
  32. # Hide the INFO-level messages sent to the logger from Azure by increasing the logging level to WARNING
  33. logging.getLogger().setLevel(logging.WARNING)
  34. for blob_file in generator:
  35. # Create the blob client
  36. blob_client = create_blob_client(blob_service_client=blob_service_client,
  37. container_name=container_name,
  38. blob_file=blob_file)
  39. # Set the storage tier
  40. blob_client.set_standard_blob_tier(standard_blob_tier=storage_tier)
  41. except azure.core.exceptions.ResourceNotFoundError:
  42. logging.error(f' The specified container, {container_name}, does not exist.')
  43. raise SystemExit
  44. def __init__(self, container_name, account_name, passphrase, storage_tier):
  45. # Set the container name variable
  46. self.container_name = container_name
  47. # Initialise necessary class variables
  48. self.passphrase = passphrase
  49. self.account_name = account_name
  50. self.storage_tier = storage_tier
  51. self.connect_str = str()
  52. self.blob_service_client = None
  53. self.container_client = None
  54. class AzureTier(object):
  55. def main(self):
  56. self.container_name, self.connect_str, self.blob_service_client, self.container_client = \
  57. client_prep(container_name=self.container_name,
  58. passphrase=self.passphrase,
  59. account_name=self.account_name,
  60. create=False)
  61. # Run the proper method depending on whether a file or a folder is requested
  62. if self.category == 'file':
  63. self.file_tier(container_client=self.container_client,
  64. object_name=self.object_name,
  65. blob_service_client=self.blob_service_client,
  66. container_name=self.container_name,
  67. storage_tier=self.storage_tier)
  68. elif self.category == 'folder':
  69. self.folder_tier(container_client=self.container_client,
  70. object_name=self.object_name,
  71. blob_service_client=self.blob_service_client,
  72. container_name=self.container_name,
  73. storage_tier=self.storage_tier)
  74. else:
  75. logging.error(f'Something is wrong. There is no {self.category} option available')
  76. raise SystemExit
  77. @staticmethod
  78. def file_tier(container_client, object_name, blob_service_client, container_name, storage_tier):
  79. """
  80. Set the storage tier for the specified file in Azure storage
  81. :param container_client: type azure.storage.blob.BlobServiceClient.ContainerClient
  82. :param object_name: type str: Name and path of file for which a SAS URL is to be created
  83. :param blob_service_client: type: azure.storage.blob.BlobServiceClient
  84. :param container_name: type str: Name of the container of interest
  85. :param storage_tier: type str: Storage tier to use for the file
  86. """
  87. # Create a generator containing all the blobs in the container
  88. generator = container_client.list_blobs()
  89. # Create a boolean to determine if the blob has been located
  90. present = False
  91. # Hide the INFO-level messages sent to the logger from Azure by increasing the logging level to WARNING
  92. logging.getLogger().setLevel(logging.WARNING)
  93. try:
  94. for blob_file in generator:
  95. # Filter for the blob name
  96. if blob_file.name == object_name:
  97. # Update the blob presence variable
  98. present = True
  99. # Create the blob client
  100. blob_client = create_blob_client(blob_service_client=blob_service_client,
  101. container_name=container_name,
  102. blob_file=blob_file)
  103. # Set the storage tier
  104. blob_client.set_standard_blob_tier(standard_blob_tier=storage_tier)
  105. # Send an error to the user that the blob could not be found
  106. if not present:
  107. logging.error(f'Could not locate the desired file {object_name} in {container_name}')
  108. raise SystemExit
  109. except azure.core.exceptions.ResourceNotFoundError:
  110. logging.error(f' The specified container, {container_name}, does not exist.')
  111. raise SystemExit
  112. @staticmethod
  113. def folder_tier(container_client, object_name, blob_service_client, container_name, storage_tier):
  114. """
  115. Set the storage tier for the specified folder in Azure storage
  116. :param container_client: type azure.storage.blob.BlobServiceClient.ContainerClient
  117. :param object_name: type str: Name and path of file for which a SAS URL is to be created
  118. :param blob_service_client: type: azure.storage.blob.BlobServiceClient
  119. :param container_name: type str: Name of the container of interest
  120. :param storage_tier: type str: Storage tier to use for the folder
  121. """
  122. # Create a generator containing all the blobs in the container
  123. generator = container_client.list_blobs()
  124. # Create a boolean to determine if the blob has been located
  125. present = False
  126. # Hide the INFO-level messages sent to the logger from Azure by increasing the logging level to WARNING
  127. logging.getLogger().setLevel(logging.WARNING)
  128. try:
  129. for blob_file in generator:
  130. # Create the path of the file by extracting the path of the file
  131. blob_path = os.path.join(os.path.split(blob_file.name)[0])
  132. # Ensure that the supplied folder path is present in the blob path
  133. if os.path.normpath(object_name) in os.path.normpath(blob_path):
  134. # Update the folder presence boolean
  135. present = True
  136. # Create the blob client
  137. blob_client = create_blob_client(blob_service_client=blob_service_client,
  138. container_name=container_name,
  139. blob_file=blob_file)
  140. # Set the storage tier
  141. blob_client.set_standard_blob_tier(standard_blob_tier=storage_tier)
  142. # Send an error to the user that the folder could not be found
  143. if not present:
  144. logging.error(f'Could not locate the desired folder {object_name} in container {container_name}')
  145. raise SystemExit
  146. except azure.core.exceptions.ResourceNotFoundError:
  147. logging.error(f' The specified container, {container_name}, does not exist.')
  148. raise SystemExit
  149. def __init__(self, object_name, container_name, account_name, passphrase, storage_tier, category):
  150. # Set the name of the file/folder to have its storage tier set
  151. self.object_name = object_name
  152. # Set the container name variable
  153. self.container_name = container_name
  154. # Initialise necessary class variables
  155. self.passphrase = passphrase
  156. self.account_name = account_name
  157. self.storage_tier = storage_tier
  158. self.category = category
  159. self.connect_str = str()
  160. self.blob_service_client = None
  161. self.container_client = None
  162. def container_tier(args):
  163. """
  164. Run the AzureContainerTier method
  165. :param args: type ArgumentParser arguments
  166. """
  167. logging.info(f'Setting the storage tier for Azure container {args.container_name} to {args.storage_tier}')
  168. # Create the container tier object
  169. container_tier_set = AzureContainerTier(container_name=args.container_name,
  170. account_name=args.account_name,
  171. passphrase=args.passphrase,
  172. storage_tier=args.storage_tier)
  173. container_tier_set.main()
  174. def file_tier(args):
  175. """
  176. Run the AzureTier method for a file
  177. :param args: type ArgumentParser arguments
  178. """
  179. logging.info(f'Setting the storage tier for file {args.file} in Azure container {args.container_name} to '
  180. f'{args.storage_tier}')
  181. # Create the file tier object
  182. file_tier_set = AzureTier(container_name=args.container_name,
  183. object_name=args.file,
  184. account_name=args.account_name,
  185. passphrase=args.passphrase,
  186. storage_tier=args.storage_tier,
  187. category='file')
  188. file_tier_set.main()
  189. def folder_tier(args):
  190. """
  191. Run the AzureTier method for a file
  192. :param args: type ArgumentParser arguments
  193. """
  194. logging.info(f'Setting the storage tier for folder {args.folder} in Azure container {args.container_name} to '
  195. f'{args.storage_tier}')
  196. # Create the folder tier object
  197. folder_tier_set = AzureTier(container_name=args.container_name,
  198. object_name=args.folder,
  199. account_name=args.account_name,
  200. passphrase=args.passphrase,
  201. storage_tier=args.storage_tier,
  202. category='folder')
  203. folder_tier_set.main()
  204. def cli():
  205. parser = ArgumentParser(description='Set the storage tier of containers/files/folders in Azure storage')
  206. # Create the parental parser, and the subparser
  207. subparsers, parent_parser = create_parent_parser(parser=parser)
  208. parent_parser.add_argument('-s', '--storage_tier',
  209. type=str,
  210. required=True,
  211. choices=['Hot', 'Cool', 'Archive'],
  212. metavar='STORAGE_TIER',
  213. help='Set the storage tier for a container/file/folder. Options are "Hot", '
  214. '"Cool", and "Archive"')
  215. # Container tier setting parser
  216. container_subparser = subparsers.add_parser(parents=[parent_parser],
  217. name='container',
  218. description='Change the storage tier of a container in Azure storage',
  219. formatter_class=RawTextHelpFormatter,
  220. help='Change the storage tier of a container in Azure storage')
  221. container_subparser.set_defaults(func=container_tier)
  222. # File tier setting parser
  223. file_subparser = subparsers.add_parser(parents=[parent_parser],
  224. name='file',
  225. description='Change the storage tier of a file in Azure storage',
  226. formatter_class=RawTextHelpFormatter,
  227. help='Change the storage tier of a file in Azure storage')
  228. file_subparser.add_argument('-f', '--file',
  229. type=str,
  230. required=True,
  231. help='Name of file in Azure storage that will have its storage tier set'
  232. 'e.g. 220202-m05722/2022-SEQ-0001_S1_L001_R1_001.fastq.gz')
  233. file_subparser.set_defaults(func=file_tier)
  234. # Folder downloading subparser
  235. folder_subparser = subparsers.add_parser(parents=[parent_parser],
  236. name='folder',
  237. description='Change the storage tier of a folder in Azure storage',
  238. formatter_class=RawTextHelpFormatter,
  239. help='Change the storage tier of a folder in Azure storage')
  240. folder_subparser.add_argument('-f', '--folder',
  241. type=str,
  242. required=True,
  243. help='Name of the folder in Azure storage that will have its storage tier set '
  244. 'e.g. InterOp')
  245. folder_subparser.set_defaults(func=folder_tier)
  246. # Set up the arguments, and run the appropriate subparser
  247. arguments = setup_arguments(parser=parser)
  248. # Return to the requested logging level, as it has been increased to WARNING to suppress the log being filled with
  249. # information from azure.core.pipeline.policies.http_logging_policy
  250. coloredlogs.install(level=arguments.verbosity.upper())
  251. logging.info('Storage tier set')
  252. # Prevent the arguments being printed to the console (they are returned in order for the tests to work)
  253. sys.stderr = open(os.devnull, 'w')
  254. return arguments
  255. if __name__ == '__main__':
  256. cli()