123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- #!/usr/bin/env python
- from azure_storage.methods import copy_blob, create_parent_parser, delete_container, delete_file, delete_folder, \
- extract_common_path, move_prep, setup_arguments
- from argparse import ArgumentParser, RawTextHelpFormatter
- import coloredlogs
- import logging
- import sys
- import os
- class AzureContainerMove(object):
- def main(self):
- # Validate the container names, and prepare all the necessary clients
- self.container_name, self.target_container, self.blob_service_client, self.source_container_client, \
- self.target_container_client = move_prep(
- passphrase=self.passphrase,
- account_name=self.account_name,
- container_name=self.container_name,
- target_container=self.target_container)
- # Rename (move) the container
- self.move_container(source_container_client=self.source_container_client,
- blob_service_client=self.blob_service_client,
- container_name=self.container_name,
- target_container=self.target_container,
- path=self.path,
- storage_tier=self.storage_tier)
- # Delete the original container once the copy is complete
- delete_container(blob_service_client=self.blob_service_client,
- container_name=self.container_name,
- account_name=self.account_name)
- @staticmethod
- def move_container(source_container_client, blob_service_client, container_name, target_container, path,
- storage_tier):
- """
- Rename (move) the specified container in Azure storage
- :param source_container_client: type azure.storage.blob.BlobServiceClient.ContainerClient for source container
- :param blob_service_client: type: azure.storage.blob.BlobServiceClient
- :param container_name: type str: Name of the container in which the folder is located
- :param target_container: type str: Name of the container into which the folder is to be moved
- :param path: type str: Path of folders in which the files are to be placed
- :param storage_tier: type str: Storage tier to use for the container
- """
- # Create a generator containing all the blobs in the container
- generator = source_container_client.list_blobs()
- for blob_file in generator:
- # Copy the file to the new container
- copy_blob(blob_file=blob_file,
- blob_service_client=blob_service_client,
- container_name=container_name,
- target_container=target_container,
- path=path,
- storage_tier=storage_tier,
- category='container')
- def __init__(self, container_name, account_name, passphrase, target_container, path, storage_tier):
- # Set the container name variable
- self.container_name = container_name
- # Initialise necessary class variables
- self.passphrase = passphrase
- self.account_name = account_name
- self.target_container = target_container
- self.path = path
- self.storage_tier = storage_tier
- self.connect_str = str()
- self.blob_service_client = None
- self.source_container_client = None
- self.target_container_client = None
- class AzureMove(object):
- def main(self):
- # Validate the container names, and prepare all the necessary clients
- self.container_name, self.target_container, self.blob_service_client, self.source_container_client, \
- self.target_container_client = move_prep(
- passphrase=self.passphrase,
- account_name=self.account_name,
- container_name=self.container_name,
- target_container=self.target_container)
- # Run the proper method depending on whether a file or a folder is requested
- if self.category == 'file':
- self.move_file(source_container_client=self.source_container_client,
- object_name=self.object_name,
- blob_service_client=self.blob_service_client,
- container_name=self.container_name,
- target_container=self.target_container,
- path=self.path,
- storage_tier=self.storage_tier)
- delete_file(container_client=self.source_container_client,
- object_name=self.object_name,
- blob_service_client=self.blob_service_client,
- container_name=self.container_name)
- elif self.category == 'folder':
- self.move_folder(source_container_client=self.source_container_client,
- object_name=self.object_name,
- blob_service_client=self.blob_service_client,
- container_name=self.container_name,
- target_container=self.target_container,
- path=self.path,
- category=self.category,
- storage_tier=self.storage_tier)
- delete_folder(container_client=self.source_container_client,
- object_name=self.object_name,
- blob_service_client=self.blob_service_client,
- container_name=self.container_name,
- account_name=self.account_name)
- else:
- logging.error(f'Something is wrong. There is no {self.category} option available')
- raise SystemExit
- @staticmethod
- def move_file(source_container_client, object_name, blob_service_client, container_name, target_container,
- path, storage_tier):
- """
- Move the specified file to the desired container in Azure storage
- :param source_container_client: type azure.storage.blob.BlobServiceClient.ContainerClient for source container
- :param object_name: type str: Name and path of folder to move in Azure storage
- :param blob_service_client: type: azure.storage.blob.BlobServiceClient
- :param container_name: type str: Name of the container in which the folder is located
- :param target_container: type str: Name of the container into which the folder is to be moved
- :param path: type str: Path of folders in which the files are to be placed
- :param storage_tier: type str: Storage tier to use for the file
- """
- # Create a generator containing all the blobs in the container
- generator = source_container_client.list_blobs()
- # Create a boolean to determine if the blob has been located
- present = False
- for blob_file in generator:
- # Filter for the blob name
- if blob_file.name == object_name:
- # Update the blob presence variable
- present = True
- # Copy the file to the new container
- copy_blob(blob_file=blob_file,
- blob_service_client=blob_service_client,
- container_name=container_name,
- target_container=target_container,
- path=path,
- storage_tier=storage_tier)
- # Send a warning to the user that the blob could not be found
- if not present:
- logging.error(f'Could not locate the desired file {object_name}')
- raise SystemExit
- @staticmethod
- def move_folder(source_container_client, object_name, blob_service_client, container_name, target_container, path,
- storage_tier, category):
- """
- Move the specified folder (and its contents) to the desired container in Azure storage
- :param source_container_client: type azure.storage.blob.BlobServiceClient.ContainerClient for source container
- :param object_name: type str: Name and path of folder to move in Azure storage
- :param blob_service_client: type: azure.storage.blob.BlobServiceClient
- :param container_name: type str: Name of the container in which the folder is located
- :param target_container: type str: Name of the container into which the folder is to be moved
- :param path: type str: Path of folders in which the files are to be placed
- :param storage_tier: type str: Storage tier to use for the moved folder
- :param category: type str: Category of object to be copied. Limited to file or folder
- """
- # Create a generator containing all the blobs in the container
- generator = source_container_client.list_blobs()
- # Create a boolean to determine if the blob has been located
- present = False
- for blob_file in generator:
- # Extract the common path between the current file and the requested folder
- common_path = extract_common_path(object_name=object_name,
- blob_file=blob_file)
- # Only copy the file if there is a common path between the object path and the blob path (they match)
- if common_path is not None:
- # Update the blob presence variable
- present = True
- # Copy the file to the new container
- copy_blob(blob_file=blob_file,
- blob_service_client=blob_service_client,
- container_name=container_name,
- target_container=target_container,
- path=path,
- object_name=object_name,
- category=category,
- common_path=common_path,
- storage_tier=storage_tier)
- # Send a warning to the user that the blob could not be found
- if not present:
- logging.error(f'Could not locate the desired folder {object_name}')
- raise SystemExit
- def __init__(self, object_name, container_name, account_name, passphrase, target_container, path,
- storage_tier, category):
- self.object_name = object_name
- # Set the container name variable
- self.container_name = container_name
- # Initialise necessary class variables
- self.passphrase = passphrase
- self.account_name = account_name
- self.target_container = target_container
- self.path = path
- self.storage_tier = storage_tier
- self.category = category
- self.connect_str = str()
- self.blob_service_client = None
- self.source_container_client = None
- self.target_container_client = None
- def container_move(args):
- """
- Run the AzureContainerMove method
- :param args: type ArgumentParser arguments
- """
- logging.info(f'Renaming container {args.container_name} to {args.target_container} in Azure storage '
- f'account {args.account_name}')
- move_container = AzureContainerMove(container_name=args.container_name,
- account_name=args.account_name,
- passphrase=args.passphrase,
- target_container=args.target_container,
- path=args.reset_path,
- storage_tier=args.storage_tier)
- move_container.main()
- def file_move(args):
- """
- Run the AzureMove method for a file
- :param args: type ArgumentParser arguments
- """
- logging.info(f'Moving file {args.file} from {args.container_name} to {args.target_container} in Azure storage '
- f'account {args.account_name}')
- move_file = AzureMove(object_name=args.file,
- container_name=args.container_name,
- account_name=args.account_name,
- passphrase=args.passphrase,
- target_container=args.target_container,
- path=args.reset_path,
- storage_tier=args.storage_tier,
- category='file')
- move_file.main()
- def folder_move(args):
- """
- Run the AzureMove method for a folder
- :param args: type ArgumentParser arguments
- """
- logging.info(f'Moving folder {args.folder} from {args.container_name} to {args.target_container} in Azure storage '
- f'account {args.account_name}')
- move_folder = AzureMove(object_name=args.folder,
- container_name=args.container_name,
- account_name=args.account_name,
- passphrase=args.passphrase,
- target_container=args.target_container,
- path=args.reset_path,
- storage_tier=args.storage_tier,
- category='folder')
- move_folder.main()
- def cli():
- parser = ArgumentParser(description='Move containers, files, or folders in Azure storage')
- # Create the parental parser, and the subparser
- subparsers, parent_parser = create_parent_parser(parser=parser)
- parent_parser.add_argument('-t', '--target_container',
- required=True,
- help='The target container to which the container/file/folder is to be moved '
- '(this can be the same as the container_name if you want to move a file/folder'
- ' within a container')
- parent_parser.add_argument('-r', '--reset_path',
- type=str,
- help='Set the path of the container/file/folder within a folder in the target container '
- 'e.g. sequence_data/220202-m05722. If you want to place it directly in the '
- 'container without any nesting, use or \'\'')
- parent_parser.add_argument('-s', '--storage_tier',
- type=str,
- default='Hot',
- choices=['Hot', 'Cool', 'Archive'],
- metavar='STORAGE_TIER',
- help='Set the storage tier for the container/file/folder to be moved. '
- 'Options are "Hot", "Cool", and "Archive". Default is Hot')
- # Container move subparser
- container_move_subparser = subparsers.add_parser(parents=[parent_parser],
- name='container',
- description='Move a container in Azure storage',
- formatter_class=RawTextHelpFormatter,
- help='Move a container in Azure storage')
- container_move_subparser.set_defaults(func=container_move)
- # File move subparser
- file_move_subparser = subparsers.add_parser(parents=[parent_parser],
- name='file',
- description='Move a file within Azure storage',
- formatter_class=RawTextHelpFormatter,
- help='Move a file within Azure storage')
- file_move_subparser.add_argument('-f', '--file',
- type=str,
- required=True,
- help='Name of blob file to move in Azure storage. '
- 'e.g. 2022-SEQ-0001_S1_L001_R1_001.fastq.gz')
- file_move_subparser.set_defaults(func=file_move)
- # Folder move subparser
- folder_move_subparser = subparsers.add_parser(parents=[parent_parser],
- name='folder',
- description='Move a folder within Azure storage',
- formatter_class=RawTextHelpFormatter,
- help='Move a folder within Azure storage')
- folder_move_subparser.add_argument('-f', '--folder',
- type=str,
- required=True,
- help='Name of folder to move in Azure storage. '
- 'e.g. InterOp')
- folder_move_subparser.set_defaults(func=folder_move)
- # Set up the arguments, and run the appropriate subparser
- arguments = setup_arguments(parser=parser)
- # Return to the requested logging level, as it has been increased to WARNING to suppress the log being filled with
- # information from azure.core.pipeline.policies.http_logging_policy
- coloredlogs.install(level=arguments.verbosity.upper())
- logging.info('Move complete')
- # Prevent the arguments being printed to the console (they are returned in order for the tests to work)
- sys.stderr = open(os.devnull, 'w')
- return arguments
- if __name__ == '__main__':
- cli()
|