|
| 1 | +import logging |
| 2 | +import click |
| 3 | +from azure.identity import DefaultAzureCredential, AzureAuthorityHosts |
| 4 | +from azure.core.exceptions import ClientAuthenticationError |
| 5 | +from azure.storage.blob import BlobServiceClient |
| 6 | + |
| 7 | + |
| 8 | +logger = logging.getLogger(__name__) |
| 9 | + |
| 10 | + |
| 11 | +class Session(object): |
| 12 | + def __init__(self, scopes = "https://storage.azure.com/.default"): |
| 13 | + """ |
| 14 | + constructor |
| 15 | +
|
| 16 | + Parameters: |
| 17 | + scopes: scopes for get_token method. Default to "https://storage.azure.com/.default" |
| 18 | + """ |
| 19 | + self.scopes = scopes |
| 20 | + |
| 21 | + def __enter__(self): |
| 22 | + return self |
| 23 | + |
| 24 | + def __exit__(self, exc_type, exc_value, traceback): |
| 25 | + self.scopes = None |
| 26 | + |
| 27 | + |
| 28 | + def get_credential(self): |
| 29 | + """ |
| 30 | + get token credential for azure. |
| 31 | +
|
| 32 | + Usage example: |
| 33 | +
|
| 34 | + from azure.storage.blob import BlobServiceClient |
| 35 | + from cbsurge.session import Session |
| 36 | +
|
| 37 | + session = Session() |
| 38 | + credential = session.get_credential() |
| 39 | +
|
| 40 | + blob_service_client = BlobServiceClient( |
| 41 | + account_url="https://<my_account_name>.blob.core.windows.net", |
| 42 | + credential=token_credential |
| 43 | + ) |
| 44 | +
|
| 45 | + Returns: |
| 46 | + Azure TokenCredential is returned if authenticated. |
| 47 | + """ |
| 48 | + credential = DefaultAzureCredential() |
| 49 | + return credential |
| 50 | + |
| 51 | + def get_token(self): |
| 52 | + """ |
| 53 | + get access token for blob storage account. This token is required for using Azure REST API. |
| 54 | +
|
| 55 | + Returns: |
| 56 | + Azure token is returned if authenticated. |
| 57 | + Raises: |
| 58 | + ClientAuthenticationError is raised if authentication failed. |
| 59 | +
|
| 60 | + ClientAuthenticationError: |
| 61 | + https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.exceptions.clientauthenticationerror?view=azure-python |
| 62 | + """ |
| 63 | + try: |
| 64 | + credential = self.get_credential() |
| 65 | + token = credential.get_token(self.scopes) |
| 66 | + return token |
| 67 | + except ClientAuthenticationError as err: |
| 68 | + logger.error("authentication failed. Please use 'rapida init' command to setup credentials.") |
| 69 | + raise err |
| 70 | + |
| 71 | + def authenticate(self): |
| 72 | + """ |
| 73 | + Authenticate to Azure through interactive browser if DefaultAzureCredential is not provideds. |
| 74 | + Authentication uses DefaultAzureCredential. |
| 75 | +
|
| 76 | + Please refer to https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python |
| 77 | + about DefaultAzureCredential api specificaiton. |
| 78 | +
|
| 79 | + Returns: |
| 80 | + Azure credential and token are returned if authenticated. If authentication failed, return None. |
| 81 | + """ |
| 82 | + try: |
| 83 | + credential = DefaultAzureCredential( |
| 84 | + exclude_interactive_browser_credential=False, |
| 85 | + ) |
| 86 | + token = credential.get_token(self.scopes) |
| 87 | + return [credential, token] |
| 88 | + except ClientAuthenticationError as err: |
| 89 | + logger.error("authentication failed.") |
| 90 | + logger.error(err) |
| 91 | + return None |
| 92 | + |
| 93 | + def get_blob_service_client(self, account_name: str) -> BlobServiceClient: |
| 94 | + """ |
| 95 | + get BlobServiceClient for account url |
| 96 | +
|
| 97 | + Usage example: |
| 98 | + with Session() as session: |
| 99 | + blob_service_client = session.get_blob_service_client( |
| 100 | + account_name="undpgeohub" |
| 101 | + ) |
| 102 | +
|
| 103 | + Parameters: |
| 104 | + account_name (str): name of storage account. https://{account_name}.blob.core.windows.net |
| 105 | + Returns: |
| 106 | + BlobServiceClient |
| 107 | + """ |
| 108 | + credential = self.get_credential() |
| 109 | + blob_service_client = BlobServiceClient( |
| 110 | + account_url=f"https://{account_name}.blob.core.windows.net", |
| 111 | + credential=credential |
| 112 | + ) |
| 113 | + return blob_service_client |
| 114 | + |
| 115 | + |
| 116 | +@click.command() |
| 117 | +@click.option('--debug', |
| 118 | + is_flag=True, |
| 119 | + default=False, |
| 120 | + help="Set log level to debug" |
| 121 | + ) |
| 122 | +def init(debug=False): |
| 123 | + """ |
| 124 | + This command setup rapida command environment by authenticating to Azure. |
| 125 | + """ |
| 126 | + logging.basicConfig(level=logging.DEBUG if debug else logging.INFO, force=True) |
| 127 | + |
| 128 | + if click.confirm('Would you like to setup rapida tool?', abort=True): |
| 129 | + # login to Azure |
| 130 | + session = Session() |
| 131 | + credential, token = session.authenticate() |
| 132 | + logger.debug(token) |
| 133 | + if token is None: |
| 134 | + logger.info("Authentication failed.Please `az login` to authenticate first.") |
| 135 | + return |
| 136 | + click.echo('Setting up was successfully done!') |
| 137 | + |
0 commit comments