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
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, [])
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"))
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