Example #1
0
    def __init__(
        self,
        tenant_id,
        client_id,
        client_secret,
        resource_group_name,
        storage_account_name,
        subscription_id=None,
        cloud="public",
    ):
        """Establish connection information."""
        self._resource_group_name = resource_group_name
        self._storage_account_name = storage_account_name
        self._factory = AzureClientFactory(subscription_id, tenant_id,
                                           client_id, client_secret, cloud)

        if not self._factory.subscription_id:
            raise AzureServiceError("Azure Service missing subscription id.")

        self._cloud_storage_account = self._factory.cloud_storage_account(
            resource_group_name, storage_account_name)

        if not self._factory.credentials:
            raise AzureServiceError(
                "Azure Service credentials are not configured.")
Example #2
0
    def __init__(self,
                 subscription_id,
                 tenant_id,
                 client_id,
                 client_secret,
                 resource_group_name,
                 storage_account_name,
                 cloud='public'):
        """Establish connection information."""
        self._resource_group_name = resource_group_name
        self._storage_account_name = storage_account_name
        self._factory = AzureClientFactory(subscription_id, tenant_id,
                                           client_id, client_secret, cloud)
        self._cloud_storage_account = self._factory.cloud_storage_account(
            resource_group_name, storage_account_name)
        try:
            self._blockblob_service = self._cloud_storage_account.create_block_blob_service(
            )
        except AzureException as error:
            raise AzureServiceError(
                'Unable to create block blob service. Error: %s', str(error))

        if not self._factory.credentials:
            raise AzureServiceError(
                'Azure Service credentials are not configured.')
Example #3
0
 def test_cloud_storage_account(self, _):
     """Test the cloud_storage_account method."""
     subscription_id = FAKE.uuid4()
     resource_group_name = FAKE.word()
     storage_account_name = FAKE.word()
     obj = AzureClientFactory(
         subscription_id=subscription_id,
         tenant_id=FAKE.uuid4(),
         client_id=FAKE.uuid4(),
         client_secret=FAKE.word(),
         cloud=random.choice(self.clouds),
     )
     with patch.object(StorageManagementClient, "storage_accounts", return_value=None):
         cloud_account = obj.cloud_storage_account(resource_group_name, storage_account_name)
         self.assertTrue(isinstance(cloud_account, BlobServiceClient))
Example #4
0
 def test_constructor(self, _):
     """Test that we can create an AzureClientFactory object."""
     obj = AzureClientFactory(subscription_id=FAKE.uuid4(),
                              tenant_id=FAKE.uuid4(),
                              client_id=FAKE.uuid4(),
                              client_secret=FAKE.word(),
                              cloud=random.choice(self.clouds))
     self.assertTrue(isinstance(obj, AzureClientFactory))
Example #5
0
 def test_subscription_id(self, _):
     """Test the subscription_id property."""
     subscription_id = FAKE.uuid4()
     obj = AzureClientFactory(subscription_id=subscription_id,
                              tenant_id=FAKE.uuid4(),
                              client_id=FAKE.uuid4(),
                              client_secret=FAKE.word(),
                              cloud=random.choice(self.clouds))
     self.assertTrue(obj.subscription_id, subscription_id)
Example #6
0
 def test_storage_client(self, _):
     """Test the storage_client property."""
     obj = AzureClientFactory(subscription_id=FAKE.uuid4(),
                              tenant_id=FAKE.uuid4(),
                              client_id=FAKE.uuid4(),
                              client_secret=FAKE.word(),
                              cloud=random.choice(self.clouds))
     self.assertTrue(isinstance(obj.storage_client,
                                StorageManagementClient))
Example #7
0
 def test_credentials(self, _):
     """Test the credentials property."""
     obj = AzureClientFactory(subscription_id=FAKE.uuid4(),
                              tenant_id=FAKE.uuid4(),
                              client_id=FAKE.uuid4(),
                              client_secret=FAKE.word(),
                              cloud=random.choice(self.clouds))
     self.assertTrue(
         isinstance(obj._credentials, ServicePrincipalCredentials))
Example #8
0
class AzureService:
    """A class to handle interactions with the Azure services."""
    def __init__(self,
                 subscription_id,
                 tenant_id,
                 client_id,
                 client_secret,
                 resource_group_name,
                 storage_account_name,
                 cloud='public'):
        """Establish connection information."""
        self._resource_group_name = resource_group_name
        self._storage_account_name = storage_account_name
        self._factory = AzureClientFactory(subscription_id, tenant_id,
                                           client_id, client_secret, cloud)
        self._cloud_storage_account = self._factory.cloud_storage_account(
            resource_group_name, storage_account_name)
        try:
            self._blockblob_service = self._cloud_storage_account.create_block_blob_service(
            )
        except AzureException as error:
            raise AzureServiceError(
                'Unable to create block blob service. Error: %s', str(error))

        if not self._factory.credentials:
            raise AzureServiceError(
                'Azure Service credentials are not configured.')

    def get_cost_export_for_key(self, key, container_name):
        """Get the latest cost export file from given storage account container."""
        report = None
        blob_list = self._blockblob_service.list_blobs(container_name)
        for blob in blob_list:
            if key == blob.name:
                report = blob
                break
        if not report:
            message = f'No cost report for report name {key} found in container {container_name}.'
            raise AzureCostReportNotFound(message)
        return report

    def download_cost_export(self, key, container_name, destination=None):
        """Download the latest cost export file from a given storage container."""
        cost_export = self.get_cost_export_for_key(key, container_name)

        file_path = destination
        if not destination:
            temp_file = NamedTemporaryFile(delete=False, suffix='.csv')
            file_path = temp_file.name
        try:
            self._blockblob_service.get_blob_to_path(container_name,
                                                     cost_export.name,
                                                     file_path)
        except AzureException as error:
            raise AzureServiceError('Failed to download cost export. Error: ',
                                    str(error))
        return file_path

    def get_latest_cost_export_for_path(self, report_path, container_name):
        """Get the latest cost export file from given storage account container."""
        latest_report = None
        blob_list = self._blockblob_service.list_blobs(container_name)
        for blob in blob_list:
            if report_path in blob.name and not latest_report:
                latest_report = blob
            elif report_path in blob.name and blob.properties.last_modified > latest_report.properties.last_modified:
                latest_report = blob
        if not latest_report:
            message = f'No cost report found in container {container_name} for '\
                      f'path {report_path}.'
            raise AzureCostReportNotFound(message)
        return latest_report

    def describe_cost_management_exports(self):
        """List cost management export."""
        cost_management_client = self._factory.cost_management_client
        scope = f'/subscriptions/{self._factory.subscription_id}'
        management_reports = cost_management_client.exports.list(scope)
        expected_resource_id = (
            f'/subscriptions/{self._factory.subscription_id}/resourceGroups/'
            f'{self._resource_group_name}/providers/Microsoft.Storage/'
            f'storageAccounts/{self._storage_account_name}')
        export_reports = []
        for report in management_reports.value:
            if report.delivery_info.destination.resource_id == expected_resource_id:
                report_def = {
                    'name': report.name,
                    'container': report.delivery_info.destination.container,
                    'directory':
                    report.delivery_info.destination.root_folder_path
                }
                export_reports.append(report_def)
        return export_reports
Example #9
0
class AzureService:
    """A class to handle interactions with the Azure services."""

    def __init__(
        self,
        tenant_id,
        client_id,
        client_secret,
        resource_group_name,
        storage_account_name,
        subscription_id=None,
        cloud="public",
    ):
        """Establish connection information."""
        self._resource_group_name = resource_group_name
        self._storage_account_name = storage_account_name
        self._factory = AzureClientFactory(subscription_id, tenant_id, client_id, client_secret, cloud)

        if not self._factory.subscription_id:
            raise AzureServiceError("Azure Service missing subscription id.")

        self._cloud_storage_account = self._factory.cloud_storage_account(resource_group_name, storage_account_name)

        if not self._factory.credentials:
            raise AzureServiceError("Azure Service credentials are not configured.")

    def get_cost_export_for_key(self, key, container_name):
        """Get the latest cost export file from given storage account container."""
        report = None
        container_client = self._cloud_storage_account.get_container_client(container_name)
        blob_list = container_client.list_blobs(name_starts_with=key)
        for blob in blob_list:
            if key == blob.name:
                report = blob
                break
        if not report:
            message = f"No cost report for report name {key} found in container {container_name}."
            raise AzureCostReportNotFound(message)
        return report

    def download_cost_export(self, key, container_name, destination=None):
        """Download the latest cost export file from a given storage container."""
        cost_export = self.get_cost_export_for_key(key, container_name)

        file_path = destination
        if not destination:
            temp_file = NamedTemporaryFile(delete=False, suffix=".csv")
            file_path = temp_file.name
        try:
            blob_client = self._cloud_storage_account.get_blob_client(container_name, cost_export.name)

            with open(file_path, "wb") as blob_download:
                blob_download.write(blob_client.download_blob().readall())
        except (AzureException, IOError) as error:
            raise AzureServiceError("Failed to download cost export. Error: ", str(error))
        return file_path

    def get_latest_cost_export_for_path(self, report_path, container_name):
        """Get the latest cost export file from given storage account container."""
        latest_report = None
        try:
            container_client = self._cloud_storage_account.get_container_client(container_name)
            blob_list = container_client.list_blobs(name_starts_with=report_path)
            for blob in blob_list:
                if report_path in blob.name and not latest_report:
                    latest_report = blob
                elif report_path in blob.name and blob.last_modified > latest_report.last_modified:
                    latest_report = blob
            if not latest_report:
                message = f"No cost report found in container {container_name} for " f"path {report_path}."
                raise AzureCostReportNotFound(message)
            return latest_report
        except HttpResponseError as httpError:
            if httpError.status_code == 403:
                message = (
                    "An authorization error occurred attempting to gather latest export"
                    f" in container {container_name} for "
                    f"path {report_path}."
                )
            else:
                message = (
                    "Unknown error occurred attempting to gather latest export"
                    f" in container {container_name} for "
                    f"path {report_path}."
                )
            error_msg = message + f" Azure Error: {httpError}."
            LOG.warning(error_msg)
            raise AzureCostReportNotFound(message)

    def describe_cost_management_exports(self):
        """List cost management export."""
        cost_management_client = self._factory.cost_management_client
        scope = f"/subscriptions/{self._factory.subscription_id}"
        expected_resource_id = (
            f"/subscriptions/{self._factory.subscription_id}/resourceGroups/"
            f"{self._resource_group_name}/providers/Microsoft.Storage/"
            f"storageAccounts/{self._storage_account_name}"
        )
        export_reports = []
        try:
            management_reports = cost_management_client.exports.list(scope)
            for report in management_reports.value:
                if report.delivery_info.destination.resource_id == expected_resource_id:
                    report_def = {
                        "name": report.name,
                        "container": report.delivery_info.destination.container,
                        "directory": report.delivery_info.destination.root_folder_path,
                    }
                    export_reports.append(report_def)
        except AzureException:
            raise AzureCostReportNotFound(AzureException)

        return export_reports