/tools/c7n_azure/c7n_azure/storage_utils.py

https://github.com/capitalone/cloud-custodian · Python · 161 lines · 128 code · 26 blank · 7 comment · 11 complexity · ae965f6249ba945f51f6b6c9dfad5cf5 MD5 · raw file

  1. # Copyright 2018 Capital One Services, LLC
  2. # Copyright The Cloud Custodian Authors.
  3. # SPDX-License-Identifier: Apache-2.0
  4. from collections import namedtuple
  5. from functools import wraps
  6. from urllib.parse import urlparse
  7. from azure.common import AzureHttpError
  8. from azure.storage.common import TokenCredential
  9. from azure.storage.blob import BlockBlobService
  10. from azure.storage.queue import QueueService
  11. from c7n_azure.constants import RESOURCE_STORAGE
  12. try:
  13. from functools import lru_cache
  14. except ImportError:
  15. from backports.functools_lru_cache import lru_cache
  16. class StorageUtilities:
  17. class Decorators:
  18. @staticmethod
  19. def handle_token_failure(func):
  20. @wraps(func)
  21. def wrapper(*a, **kw):
  22. try:
  23. return func(*a, **kw)
  24. except AzureHttpError as e:
  25. if e.error_code == 'AuthenticationFailed':
  26. StorageUtilities.get_storage_from_uri.cache_clear()
  27. StorageUtilities.get_storage_token.cache_clear()
  28. StorageUtilities.get_storage_primary_key.cache_clear()
  29. return func(*a, **kw)
  30. else:
  31. raise e
  32. return wrapper
  33. @staticmethod
  34. @Decorators.handle_token_failure
  35. def get_blob_client_by_uri(storage_uri, session):
  36. storage = StorageUtilities.get_storage_from_uri(storage_uri, session)
  37. blob_service = BlockBlobService(
  38. account_name=storage.storage_name,
  39. token_credential=storage.token)
  40. blob_service.create_container(storage.container_name)
  41. return blob_service, storage.container_name, storage.file_prefix
  42. @staticmethod
  43. @Decorators.handle_token_failure
  44. def get_blob_client_from_storage_account(resource_group, name, session, sas_generation=False):
  45. # sas tokens can only be generated from clients created from account keys
  46. primary_key = token = None
  47. if sas_generation:
  48. primary_key = StorageUtilities.get_storage_primary_key(resource_group, name, session)
  49. else:
  50. token = StorageUtilities.get_storage_token(session)
  51. return BlockBlobService(
  52. account_name=name,
  53. account_key=primary_key,
  54. token_credential=token
  55. )
  56. @staticmethod
  57. @Decorators.handle_token_failure
  58. def get_queue_client_by_uri(queue_uri, session):
  59. storage = StorageUtilities.get_storage_from_uri(queue_uri, session)
  60. queue_service = QueueService(
  61. account_name=storage.storage_name,
  62. token_credential=storage.token)
  63. queue_service.create_queue(storage.container_name)
  64. return queue_service, storage.container_name
  65. @staticmethod
  66. @Decorators.handle_token_failure
  67. def get_queue_client_by_storage_account(storage_account, session):
  68. token = StorageUtilities.get_storage_token(session)
  69. queue_service = QueueService(
  70. account_name=storage_account.name,
  71. token_credential=token)
  72. return queue_service
  73. @staticmethod
  74. @Decorators.handle_token_failure
  75. def create_queue_from_storage_account(storage_account, name, session):
  76. token = StorageUtilities.get_storage_token(session)
  77. queue_service = QueueService(
  78. account_name=storage_account.name,
  79. token_credential=token)
  80. return queue_service.create_queue(name)
  81. @staticmethod
  82. @Decorators.handle_token_failure
  83. def delete_queue_from_storage_account(storage_account, name, session):
  84. token = StorageUtilities.get_storage_token(session)
  85. queue_service = QueueService(
  86. account_name=storage_account.name,
  87. token_credential=token)
  88. return queue_service.delete_queue(name)
  89. @staticmethod
  90. @Decorators.handle_token_failure
  91. def put_queue_message(queue_service, queue_name, content):
  92. return queue_service.put_message(queue_name, content)
  93. @staticmethod
  94. @Decorators.handle_token_failure
  95. def get_queue_messages(queue_service, queue_name, num_messages=None, visibility_timeout=None):
  96. # Default message visibility timeout is 30 seconds
  97. # so you are expected to delete message within 30 seconds
  98. # if you have successfully processed it
  99. return queue_service.get_messages(queue_name,
  100. num_messages=num_messages,
  101. visibility_timeout=visibility_timeout)
  102. @staticmethod
  103. @Decorators.handle_token_failure
  104. def delete_queue_message(queue_service, queue_name, message):
  105. queue_service.delete_message(queue_name, message.id, message.pop_receipt)
  106. @staticmethod
  107. @lru_cache()
  108. def get_storage_token(session):
  109. if session.resource_namespace != RESOURCE_STORAGE:
  110. session = session.get_session_for_resource(RESOURCE_STORAGE)
  111. return TokenCredential(session.get_bearer_token())
  112. @staticmethod
  113. @lru_cache()
  114. def get_storage_primary_key(resource_group, name, session):
  115. storage_client = session.client('azure.mgmt.storage.StorageManagementClient')
  116. storage_keys = storage_client.storage_accounts.list_keys(resource_group, name)
  117. return storage_keys.keys[0].value
  118. @staticmethod
  119. @lru_cache()
  120. def get_storage_from_uri(storage_uri, session):
  121. parts = urlparse(storage_uri)
  122. storage_name = str(parts.netloc).partition('.')[0]
  123. path_parts = parts.path.strip('/').split('/', 1)
  124. container_name = path_parts[0]
  125. if len(path_parts) > 1:
  126. prefix = path_parts[1]
  127. else:
  128. prefix = ""
  129. token = StorageUtilities.get_storage_token(session)
  130. Storage = namedtuple('Storage', 'container_name, storage_name, token, file_prefix')
  131. return Storage(
  132. container_name=container_name,
  133. storage_name=storage_name,
  134. token=token,
  135. file_prefix=prefix)