Пример #1
0
    def test_download_cost_report_exception(self, mock_factory):
        """Test that function handles a raised exception."""
        key = FAKE.word()
        mock_blob = Mock(last_modified=Mock(date=Mock(
            return_value=datetime.now())))
        name_attr = PropertyMock(return_value=key)
        type(
            mock_blob).name = name_attr  # kludge to set name attribute on Mock

        mock_factory.return_value = Mock(
            spec=AzureClientFactory,
            cloud_storage_account=Mock(return_value=Mock(
                spec=BlobServiceClient,
                get_blob_client=Mock(side_effect=AdalError("test error")),
                get_container_client=Mock(
                    return_value=Mock(spec=ContainerClient,
                                      list_blobs=Mock(
                                          return_value=[mock_blob]))),
            )),
        )
        with self.assertRaises(AzureServiceError):
            service = AzureService(self.tenant_id, self.client_id,
                                   self.client_secret,
                                   self.resource_group_name,
                                   self.storage_account_name)
            service.download_cost_export(key=key, container_name=FAKE.word())
Пример #2
0
    def setUp(self, mock_factory):
        """Set up each test."""
        super().setUp()
        self.subscription_id = FAKE.uuid4()
        self.tenant_id = FAKE.uuid4()
        self.client_id = FAKE.uuid4()
        self.client_secret = FAKE.word()
        self.resource_group_name = FAKE.word()
        self.storage_account_name = FAKE.word()

        self.container_name = FAKE.word()
        self.current_date_time = datetime.today()
        self.export_directory = FAKE.word()
        mock_factory.return_value = MockAzureClientFactory(
            self.subscription_id,
            self.container_name,
            self.current_date_time,
            self.export_directory,
            self.resource_group_name,
            self.storage_account_name,
        )

        self.client = AzureService(
            subscription_id=self.subscription_id,
            tenant_id=self.tenant_id,
            client_id=self.client_id,
            client_secret=self.client_secret,
            resource_group_name=self.resource_group_name,
            storage_account_name=self.storage_account_name,
        )
Пример #3
0
    def cost_usage_source_is_reachable(self, credential_name, storage_resource_name):
        """
        Verify that the cost usage report source is reachable by Koku.

        Implemented by provider specific class.  An account validation and
        connectivity check is to be done.

        Args:
            credential (dict): Azure credentials dict

            example: {'subscription_id': 'f695f74f-36a4-4112-9fe6-74415fac75a2',
                      'tenant_id': '319d4d72-7ddc-45d0-9d63-a2db0a36e048',
                      'client_id': 'ce26bd50-2e5a-4eb7-9504-a05a79568e25',
                      'client_secret': 'abc123' }

            source_name (dict): Identifier of the cost usage report source

            example: { 'resource_group': 'My Resource Group 1',
                       'storage_account': 'My Storage Account 2'

        Returns:
            None

        Raises:
            ValidationError: Error string

        """
        key = "billing_source.data_source"

        azure_service = None

        if not (isinstance(credential_name, dict) and isinstance(storage_resource_name, dict)):
            message = f"Resource group and/or Storage account must be a dict"
            raise ValidationError(error_obj(key, message))

        resource_group = storage_resource_name.get("resource_group")
        storage_account = storage_resource_name.get("storage_account")
        if not (resource_group and storage_account):
            message = "resource_group or storage_account is undefined."
            raise ValidationError(error_obj(key, message))

        try:
            azure_service = AzureService(
                **credential_name, resource_group_name=resource_group, storage_account_name=storage_account
            )
            azure_client = AzureClientFactory(**credential_name)
            storage_accounts = azure_client.storage_client.storage_accounts
            storage_account = storage_accounts.get_properties(resource_group, storage_account)
            if azure_service and not azure_service.describe_cost_management_exports():
                message = "Cost management export was not found."
                raise ValidationError(error_obj(key, message))
        except AzureCostReportNotFound as costreport_err:
            raise ValidationError(error_obj(key, str(costreport_err)))
        except (AdalError, AzureException, AzureServiceError, ClientException, TypeError) as exc:
            raise ValidationError(error_obj(key, str(exc)))

        return True
Пример #4
0
    def test_describe_cost_management_exports_wrong_account(
            self, mock_factory):
        """Test that cost management exports are not returned from incorrect account."""
        mock_factory.return_value = MockAzureClientFactory(
            self.subscription_id, self.container_name, self.current_date_time,
            self.export_directory, self.resource_group_name,
            self.storage_account_name)

        client = AzureService(subscription_id=self.subscription_id,
                              tenant_id=self.tenant_id,
                              client_id=self.client_id,
                              client_secret=self.client_secret,
                              resource_group_name=self.resource_group_name,
                              storage_account_name='wrongaccount')

        exports = client.describe_cost_management_exports()
        self.assertEquals(exports, [])
Пример #5
0
 def test_get_latest_cost_export_for_path_exception(self, mock_factory):
     """Test that function handles a raised exception."""
     mock_factory.return_value = Mock(
         spec=AzureClientFactory,
         cloud_storage_account=Mock(return_value=Mock(
             spec=BlobServiceClient,
             get_container_client=Mock(return_value=Mock(
                 spec=ContainerClient,
                 list_blobs=Mock(side_effect=AdalError("test error")))),
         )),
     )
     with self.assertRaises(AzureServiceError):
         service = AzureService(self.tenant_id, self.client_id,
                                self.client_secret,
                                self.resource_group_name,
                                self.storage_account_name)
         service.get_latest_cost_export_for_path(report_path=FAKE.word(),
                                                 container_name=FAKE.word())
Пример #6
0
    def test_init_no_subscription_id(self, mock_factory):
        """Test that exception is raized with no subscription id provided."""
        class MockAzureFactory:
            subscription_id = None

        factory = MockAzureFactory()
        mock_factory.return_value = factory
        with self.assertRaises(AzureServiceError):
            AzureService(self.tenant_id, self.client_id, self.client_secret,
                         self.resource_group_name, self.storage_account_name)
Пример #7
0
    def _get_azure_client(credentials, billing_source):
        subscription_id = credentials.get('subscription_id')
        tenant_id = credentials.get('tenant_id')
        client_id = credentials.get('client_id')
        client_secret = credentials.get('client_secret')
        resource_group_name = billing_source.get('resource_group')
        storage_account_name = billing_source.get('storage_account')

        service = AzureService(subscription_id, tenant_id, client_id, client_secret,
                               resource_group_name, storage_account_name)
        return service
Пример #8
0
    def _get_azure_client(credentials, data_source):
        subscription_id = credentials.get("subscription_id")
        tenant_id = credentials.get("tenant_id")
        client_id = credentials.get("client_id")
        client_secret = credentials.get("client_secret")
        resource_group_name = data_source.get("resource_group")
        storage_account_name = data_source.get("storage_account")

        service = AzureService(tenant_id, client_id, client_secret,
                               resource_group_name, storage_account_name,
                               subscription_id)
        return service
Пример #9
0
class AzureServiceTest(MasuTestCase):
    """Test Cases for the AzureService object."""
    @patch("masu.external.downloader.azure.azure_service.AzureClientFactory")
    def setUp(self, mock_factory):
        """Set up each test."""
        super().setUp()
        self.subscription_id = FAKE.uuid4()
        self.tenant_id = FAKE.uuid4()
        self.client_id = FAKE.uuid4()
        self.client_secret = FAKE.word()
        self.resource_group_name = FAKE.word()
        self.storage_account_name = FAKE.word()

        self.container_name = FAKE.word()
        self.current_date_time = datetime.today()
        self.export_directory = FAKE.word()
        mock_factory.return_value = MockAzureClientFactory(
            self.subscription_id,
            self.container_name,
            self.current_date_time,
            self.export_directory,
            self.resource_group_name,
            self.storage_account_name,
        )

        self.client = AzureService(
            subscription_id=self.subscription_id,
            tenant_id=self.tenant_id,
            client_id=self.client_id,
            client_secret=self.client_secret,
            resource_group_name=self.resource_group_name,
            storage_account_name=self.storage_account_name,
        )

    def test_initializer(self):
        """Test the AzureService initializer."""
        self.assertIsNotNone(self.client._factory)
        self.assertIsNotNone(self.client._cloud_storage_account)

    def test_get_cost_export_for_key(self):
        """Test that a cost export is retrieved by a key."""
        today = self.current_date_time
        yesterday = today - relativedelta(days=1)
        test_matrix = [
            {
                "key":
                "{}_{}_day_{}".format(self.container_name, "blob", today.day),
                "expected_date":
                today.date()
            },
            {
                "key":
                "{}_{}_day_{}".format(self.container_name, "blob",
                                      yesterday.day),
                "expected_date":
                yesterday.date(),
            },
        ]

        for test in test_matrix:
            key = test.get("key")
            expected_modified_date = test.get("expected_date")
            cost_export = self.client.get_cost_export_for_key(
                key, self.container_name)
            self.assertIsNotNone(cost_export)
            self.assertEquals(cost_export.name, key)
            self.assertEquals(cost_export.properties.last_modified.date(),
                              expected_modified_date)

    def test_get_cost_export_for_missing_key(self):
        """Test that a cost export is not retrieved by an incorrect key."""
        key = "{}_{}_wrong".format(self.container_name, "blob")
        with self.assertRaises(AzureCostReportNotFound):
            self.client.get_cost_export_for_key(key, self.container_name)

    def test_get_latest_cost_export_for_path(self):
        """Test that the latest cost export is returned for a given path."""
        report_path = "{}_{}".format(self.container_name, "blob")
        cost_export = self.client.get_latest_cost_export_for_path(
            report_path, self.container_name)
        self.assertEquals(cost_export.properties.last_modified.date(),
                          self.current_date_time.date())

    def test_get_latest_cost_export_for_path_missing(self):
        """Test that the no cost export is returned for a missing path."""
        report_path = FAKE.word()
        with self.assertRaises(AzureCostReportNotFound):
            self.client.get_latest_cost_export_for_path(
                report_path, self.container_name)

    def test_describe_cost_management_exports(self):
        """Test that cost management exports are returned for the account."""
        exports = self.client.describe_cost_management_exports()
        self.assertEquals(len(exports), 2)
        for export in exports:
            self.assertEquals(export.get("container"), self.container_name)
            self.assertEquals(export.get("directory"), self.export_directory)
            self.assertIn("{}_{}".format(self.container_name, "blob"),
                          export.get("name"))

    @patch("masu.external.downloader.azure.azure_service.AzureClientFactory")
    def test_describe_cost_management_exports_wrong_account(
            self, mock_factory):
        """Test that cost management exports are not returned from incorrect account."""
        mock_factory.return_value = MockAzureClientFactory(
            self.subscription_id,
            self.container_name,
            self.current_date_time,
            self.export_directory,
            self.resource_group_name,
            self.storage_account_name,
        )

        client = AzureService(
            subscription_id=self.subscription_id,
            tenant_id=self.tenant_id,
            client_id=self.client_id,
            client_secret=self.client_secret,
            resource_group_name=self.resource_group_name,
            storage_account_name="wrongaccount",
        )

        exports = client.describe_cost_management_exports()
        self.assertEquals(exports, [])

    def test_download_cost_export(self):
        """Test that cost management exports are downloaded."""
        key = "{}_{}_day_{}".format(self.container_name, "blob",
                                    self.current_date_time.day)
        file_path = self.client.download_cost_export(key, self.container_name)
        self.assertTrue(file_path.endswith(".csv"))
Пример #10
0
    def get_mock_client(self, blob_list=[], cost_exports=[]):
        """Generate an AzureService instance with mocked AzureClientFactory.

        Args:
            blob_list (list<Mock>) A list of Mock objects.

                    The blob_list Mock objects must have these attributes:

                        - name

            cost_exports (list<Mock>) A list of Mock objects.

                    The cost_exports Mock objects must have these
                    attributes:

                        - name
                        - delivery_info.destination.container
                        - delivery_info.destination.root_folder_path
                        - delivery_info.destination.resource_id

        Returns:
            (AzureService) An instance of AzureService with mocked AzureClientFactory
        """
        fake_data = FAKE.binary(length=1024 * 64)

        client = None
        with patch(
                "masu.external.downloader.azure.azure_service.AzureClientFactory",
                spec=AzureClientFactory) as mock_factory:
            mock_factory.return_value = Mock(  # AzureClientFactory()
                spec=AzureClientFactory,
                cloud_storage_account=Mock(
                    return_value=Mock(  # .cloud_storage_account()
                        spec=BlobServiceClient,
                        get_blob_client=Mock(
                            return_value=Mock(  # .get_blob_client()
                                spec=BlobClient,
                                # .download_blob().readall()
                                download_blob=Mock(return_value=Mock(
                                    readall=Mock(return_value=fake_data))),
                            )),
                        get_container_client=Mock(
                            # .get_container_client().list_blobs()
                            return_value=Mock(spec=ContainerClient,
                                              list_blobs=Mock(
                                                  return_value=blob_list))),
                    )),
                # .cost_management_client.exports.list().value
                cost_management_client=Mock(exports=Mock(list=Mock(
                    return_value=Mock(value=cost_exports)))),
                # .subscription_id
                subscription_id=self.subscription_id,
            )
            client = AzureService(
                self.tenant_id,
                self.client_id,
                self.client_secret,
                self.resource_group_name,
                self.storage_account_name,
                self.subscription_id,
            )
        return client
Пример #11
0
    def cost_usage_source_is_reachable(self, credentials, data_source):
        """
        Verify that the cost usage report source is reachable by Koku.

        Implemented by provider specific class.  An account validation and
        connectivity check is to be done.

        Args:
            credentials (dict): Azure credentials dict

            example: {'subscription_id': 'f695f74f-36a4-4112-9fe6-74415fac75a2',
                      'tenant_id': '319d4d72-7ddc-45d0-9d63-a2db0a36e048',
                      'client_id': 'ce26bd50-2e5a-4eb7-9504-a05a79568e25',
                      'client_secret': 'abc123' }

            data_source (dict): Identifier of the cost usage report source

            example: { 'resource_group': 'My Resource Group 1',
                       'storage_account': 'My Storage Account 2'

        Returns:
            None

        Raises:
            ValidationError: Error string

        """
        key = "azure.error"

        azure_service = None

        if not (isinstance(credentials, dict)
                and isinstance(data_source, dict)):
            message = "Resource group and/or Storage account must be a dict"
            raise ValidationError(error_obj(key, message))

        resource_group = data_source.get("resource_group")
        storage_account = data_source.get("storage_account")
        subscription_id = credentials.get("subscription_id")

        self._verify_patch_entries(subscription_id, resource_group,
                                   storage_account)

        try:
            azure_service = AzureService(**credentials,
                                         resource_group_name=resource_group,
                                         storage_account_name=storage_account)
            azure_client = AzureClientFactory(**credentials)
            storage_accounts = azure_client.storage_client.storage_accounts
            storage_account = storage_accounts.get_properties(
                resource_group, storage_account)
            if azure_service and not azure_service.describe_cost_management_exports(
            ):
                key = ProviderErrors.AZURE_NO_REPORT_FOUND
                message = ProviderErrors.AZURE_MISSING_EXPORT_MESSAGE
                raise ValidationError(error_obj(key, message))
        except AzureCostReportNotFound as costreport_err:
            key = ProviderErrors.AZURE_BILLING_SOURCE_NOT_FOUND
            raise ValidationError(error_obj(key, str(costreport_err)))
        except (AdalError, AzureException, AzureServiceError, ClientException,
                TypeError) as exc:
            key = ProviderErrors.AZURE_CLIENT_ERROR
            raise ValidationError(error_obj(key, str(exc)))

        return True