Skip to content

Commit 3870f77

Browse files
bacciottilcouzens
andauthored
[COST-5627] Fix Azure default extension issue (#5394)
* Making extension parameter optional. Co-authored-by: Luke Couzens <[email protected]>
1 parent 3d8ded0 commit 3870f77

File tree

4 files changed

+26
-82
lines changed

4 files changed

+26
-82
lines changed

koku/masu/external/downloader/azure/azure_report_downloader.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
from masu.util.aws.common import copy_local_report_file_to_s3_bucket
2727
from masu.util.aws.common import get_or_clear_daily_s3_by_date
2828
from masu.util.azure import common as utils
29-
from masu.util.azure.common import AzureBlobExtension
3029

3130
DATA_DIR = Config.TMP_DIR
3231
LOG = logging.getLogger(__name__)
@@ -272,7 +271,7 @@ def _get_manifest(self, date_time): # noqa: C901
272271
273272
"""
274273
manifest = {}
275-
compression_mode = AzureBlobExtension.csv.value # Default value
274+
compression_mode = None
276275
if self.ingress_reports:
277276
reports = [report.split(f"{self.container_name}/")[1] for report in self.ingress_reports]
278277
year = date_time.strftime("%Y")
@@ -305,7 +304,7 @@ def _get_manifest(self, date_time): # noqa: C901
305304
except AzureCostReportNotFound as ex:
306305
json_manifest = None
307306
msg = f"No JSON manifest exists. {ex}"
308-
LOG.debug(msg)
307+
LOG.info(msg)
309308
if json_manifest:
310309
report_name = json_manifest.name
311310
last_modified = json_manifest.last_modified
@@ -332,9 +331,7 @@ def _get_manifest(self, date_time): # noqa: C901
332331
manifest["reportKeys"] = [blob["blobName"] for blob in manifest_json["blobs"]]
333332
else:
334333
try:
335-
blob = self._azure_client.get_latest_cost_export_for_path(
336-
report_path, self.container_name, compression_mode
337-
)
334+
blob = self._azure_client.get_latest_cost_export_for_path(report_path, self.container_name)
338335
except AzureCostReportNotFound as ex:
339336
msg = f"Unable to find manifest. Error: {ex}"
340337
LOG.info(log_json(self.tracing_id, msg=msg, context=self.context))

koku/masu/external/downloader/azure/azure_service.py

+14-25
Original file line numberDiff line numberDiff line change
@@ -64,28 +64,26 @@ def __init__(
6464
raise AzureServiceError("Azure Service credentials are not configured.")
6565

6666
def _get_latest_blob(
67-
self, report_path: str, blobs: list[BlobProperties], extension: str
67+
self, report_path: str, blobs: list[BlobProperties], extension: t.Optional[str] = None
6868
) -> t.Optional[BlobProperties]:
6969
latest_blob = None
7070
for blob in blobs:
71-
if not blob.name.endswith(extension):
71+
if extension and not blob.name.endswith(extension):
7272
continue
73-
74-
if report_path in blob.name and not latest_blob:
75-
latest_blob = blob
76-
elif report_path in blob.name and blob.last_modified > latest_blob.last_modified:
77-
latest_blob = blob
73+
if report_path in blob.name:
74+
if not latest_blob or blob.last_modified > latest_blob.last_modified:
75+
latest_blob = blob
7876
return latest_blob
7977

8078
def _get_latest_blob_for_path(
8179
self,
8280
report_path: str,
8381
container_name: str,
84-
extension: str,
82+
extension: t.Optional[str] = None,
8583
) -> BlobProperties:
8684
"""Get the latest file with the specified extension from given storage account container."""
8785

88-
latest_report = None
86+
latest_file = None
8987
if not container_name:
9088
message = "Unable to gather latest file as container name is not provided."
9189
LOG.warning(message)
@@ -118,15 +116,12 @@ def _get_latest_blob_for_path(
118116
LOG.warning(error_msg)
119117
raise AzureCostReportNotFound(message)
120118

121-
latest_report = self._get_latest_blob(report_path, blobs, extension)
122-
if not latest_report:
123-
message = (
124-
f"No file with extension '{extension}' found in container "
125-
f"'{container_name}' for path '{report_path}'."
126-
)
119+
latest_file = self._get_latest_blob(report_path, blobs, extension)
120+
if not latest_file:
121+
message = f"No file found in container " f"'{container_name}' for path '{report_path}'."
127122
raise AzureCostReportNotFound(message)
128123

129-
return latest_report
124+
return latest_file
130125

131126
def _list_blobs(self, starts_with: str, container_name: str) -> list[BlobProperties]:
132127
try:
@@ -158,9 +153,7 @@ def get_file_for_key(self, key: str, container_name: str) -> BlobProperties:
158153

159154
return report
160155

161-
def get_latest_cost_export_for_path(
162-
self, report_path: str, container_name: str, compression: str
163-
) -> BlobProperties:
156+
def get_latest_cost_export_for_path(self, report_path: str, container_name: str) -> BlobProperties:
164157
"""
165158
Get the latest cost export for a given path and container based on the compression type.
166159
@@ -176,14 +169,10 @@ def get_latest_cost_export_for_path(
176169
ValueError: If the compression type is not 'gzip' or 'csv'.
177170
AzureCostReportNotFound: If no blob is found for the given path and container.
178171
"""
179-
valid_compressions = [AzureBlobExtension.gzip.value, AzureBlobExtension.csv.value]
180-
if compression not in valid_compressions:
181-
raise ValueError(f"Invalid compression type: {compression}. Expected one of: {valid_compressions}.")
182-
183-
return self._get_latest_blob_for_path(report_path, container_name, compression)
172+
return self._get_latest_blob_for_path(report_path, container_name)
184173

185174
def get_latest_manifest_for_path(self, report_path: str, container_name: str) -> BlobProperties:
186-
return self._get_latest_blob_for_path(report_path, container_name, AzureBlobExtension.manifest.value)
175+
return self._get_latest_blob_for_path(report_path, container_name, AzureBlobExtension.json.value)
187176

188177
def download_file(
189178
self,

koku/masu/test/external/downloader/azure/test_azure_report_downloader.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def test_get_ingress_manifest(self):
226226
manifest, _ = self.ingress_downloader._get_manifest(self.mock_data.test_date)
227227

228228
self.assertEqual(manifest.get("reportKeys"), [self.mock_data.ingress_report])
229-
self.assertEqual(manifest.get("Compression"), AzureBlobExtension.csv.value)
229+
self.assertEqual(manifest.get("Compression"), None)
230230
self.assertEqual(manifest.get("billingPeriod").get("start"), expected_start)
231231
self.assertEqual(manifest.get("billingPeriod").get("end"), expected_end)
232232

@@ -249,7 +249,7 @@ def test_get_manifest(self):
249249

250250
self.assertEqual(manifest.get("assemblyId"), self.mock_data.export_uuid)
251251
self.assertEqual(manifest.get("reportKeys"), [self.mock_data.export_file])
252-
self.assertEqual(manifest.get("Compression"), AzureBlobExtension.csv.value)
252+
self.assertEqual(manifest.get("Compression"), None)
253253
self.assertEqual(manifest.get("billingPeriod").get("start"), expected_start)
254254
self.assertEqual(manifest.get("billingPeriod").get("end"), expected_end)
255255

koku/masu/test/external/downloader/azure/test_azure_services.py

+7-49
Original file line numberDiff line numberDiff line change
@@ -210,15 +210,15 @@ def test_get_latest_cost_export_for_path(self):
210210
type(mock_blob).name = name_attr # kludge to set name attribute on Mock
211211

212212
svc = self.get_mock_client(blob_list=[mock_blob])
213-
cost_export = svc.get_latest_cost_export_for_path(report_path, self.container_name, ".csv.gz")
213+
cost_export = svc.get_latest_cost_export_for_path(report_path, self.container_name)
214214
self.assertEqual(cost_export.last_modified.date(), self.current_date_time.date())
215215

216216
def test_get_latest_cost_export_for_path_missing(self):
217217
"""Test that the no cost export is returned for a missing path."""
218218
report_path = FAKE.word()
219219
svc = self.get_mock_client()
220220
with self.assertRaises(AzureCostReportNotFound):
221-
svc.get_latest_cost_export_for_path(report_path, self.container_name, ".csv.gz")
221+
svc.get_latest_cost_export_for_path(report_path, self.container_name)
222222

223223
def test_describe_cost_management_exports(self):
224224
"""Test that cost management exports are returned for the account."""
@@ -259,7 +259,7 @@ def test_get_latest_cost_export_http_error(self):
259259
svc = self.get_mock_client(blob_list=[mock_blob])
260260
svc._cloud_storage_account.get_container_client.side_effect = throw_azure_http_error
261261
with self.assertRaises(AzureCostReportNotFound):
262-
svc.get_latest_cost_export_for_path(report_path, self.container_name, ".csv.gz")
262+
svc.get_latest_cost_export_for_path(report_path, self.container_name)
263263

264264
def test_get_latest_cost_export_http_error_403(self):
265265
"""Test that the latest cost export catches the error for Azure HttpError 403."""
@@ -272,7 +272,7 @@ def test_get_latest_cost_export_http_error_403(self):
272272
svc = self.get_mock_client(blob_list=[mock_blob])
273273
svc._cloud_storage_account.get_container_client.side_effect = throw_azure_http_error_403
274274
with self.assertRaises(AzureCostReportNotFound):
275-
svc.get_latest_cost_export_for_path(report_path, self.container_name, ".csv.gz")
275+
svc.get_latest_cost_export_for_path(report_path, self.container_name)
276276

277277
def test_get_latest_cost_export_no_container(self):
278278
"""Test that the latest cost export catches the error for no container."""
@@ -285,7 +285,7 @@ def test_get_latest_cost_export_no_container(self):
285285

286286
svc = self.get_mock_client(blob_list=[mock_blob])
287287
with self.assertRaises(AzureCostReportNotFound):
288-
svc.get_latest_cost_export_for_path(report_path, container_name, ".csv.gz")
288+
svc.get_latest_cost_export_for_path(report_path, container_name)
289289

290290
def test_get_latest_manifest_for_path(self):
291291
"""Given a list of blobs with multiple manifests, ensure the latest one is returned"""
@@ -422,9 +422,7 @@ def test_get_latest_cost_export_for_path_exception(self, mock_factory):
422422
service = AzureService(
423423
self.tenant_id, self.client_id, self.client_secret, self.resource_group_name, self.storage_account_name
424424
)
425-
service.get_latest_cost_export_for_path(
426-
report_path=FAKE.word(), container_name=FAKE.word(), compression=".csv.gz"
427-
)
425+
service.get_latest_cost_export_for_path(report_path=FAKE.word(), container_name=FAKE.word())
428426

429427
def test_describe_cost_management_exports_with_scope_and_name(self):
430428
"""Test that cost management exports using scope and name are returned for the account."""
@@ -465,7 +463,6 @@ def test_get_latest_blob(self):
465463
"""
466464
report_path = "/container/report/path"
467465
blobs = (
468-
FakeBlob(f"{report_path}/_manifest.json", datetime(2022, 12, 18)),
469466
FakeBlob(f"{report_path}/file01.csv", datetime(2022, 12, 16)),
470467
FakeBlob(f"{report_path}/file02.csv", datetime(2022, 12, 15)),
471468
FakeBlob("some/other/path/file01.csv", datetime(2022, 12, 1)),
@@ -487,7 +484,7 @@ def test_get_latest_cost_export_missing_container(self):
487484
svc = self.get_mock_client(blob_list=[mock_blob])
488485
svc._cloud_storage_account.get_container_client.side_effect = ResourceNotFoundError("Oops!")
489486
with self.assertRaises(AzureCostReportNotFound):
490-
svc.get_latest_cost_export_for_path(report_path, self.container_name, ".csv.gz")
487+
svc.get_latest_cost_export_for_path(report_path, self.container_name)
491488

492489
@patch("masu.external.downloader.azure.azure_service.AzureClientFactory")
493490
def test_azure_service_missing_credentials(self, mock_factory):
@@ -507,27 +504,6 @@ def test_azure_service_missing_credentials(self, mock_factory):
507504

508505
self.assertIn("Azure Service credentials are not configured.", str(context.exception))
509506

510-
@patch("masu.external.downloader.azure.azure_service.AzureClientFactory")
511-
@patch.object(AzureService, "_get_latest_blob_for_path")
512-
def test_get_latest_cost_export_for_path_invalid_compression(self, mock_get_latest_blob, mock_factory):
513-
"""Test when an invalid compression type is provided and ValueError is raised."""
514-
mock_get_latest_blob.return_value = None
515-
mock_factory.return_value.credentials = Mock()
516-
517-
service = AzureService(
518-
tenant_id="fake_tenant_id",
519-
client_id="fake_client_id",
520-
client_secret="fake_client_secret",
521-
resource_group_name="fake_resource_group",
522-
storage_account_name="fake_storage_account",
523-
subscription_id="fake_subscription_id",
524-
)
525-
526-
with self.assertRaises(ValueError) as context:
527-
service.get_latest_cost_export_for_path("fake_report_path", "fake_container_name", "invalid_compression")
528-
529-
self.assertIn("Invalid compression type", str(context.exception))
530-
531507
@patch("masu.external.downloader.azure.azure_service.AzureService._list_blobs")
532508
@patch("masu.external.downloader.azure.azure_service.AzureClientFactory")
533509
@patch("masu.external.downloader.azure.azure_service.NamedTemporaryFile")
@@ -627,24 +603,6 @@ def test_download_file_raises_exception(self, mock_tempfile, mock_client_factory
627603

628604
self.assertIn("Failed to download cost export", str(context.exception))
629605

630-
@patch("masu.external.downloader.azure.azure_service.AzureClientFactory")
631-
def test_invalid_compression_type(self, mock_factory):
632-
"""Test that an invalid compression type raises an exception."""
633-
634-
service = AzureService(
635-
tenant_id="fake_tenant_id",
636-
client_id="fake_client_id",
637-
client_secret="fake_client_secret",
638-
resource_group_name="fake_resource_group",
639-
storage_account_name="fake_storage_account",
640-
subscription_id="fake_subscription_id",
641-
)
642-
643-
with self.assertRaises(ValueError) as context:
644-
service.get_latest_cost_export_for_path("fake_report_path", "fake_container_name", "invalid_compression")
645-
646-
self.assertIn("Invalid compression type", str(context.exception))
647-
648606
@patch("masu.external.downloader.azure.azure_service.AzureService._list_blobs")
649607
@patch("masu.external.downloader.azure.azure_service.AzureClientFactory")
650608
@patch("masu.external.downloader.azure.azure_service.NamedTemporaryFile")

0 commit comments

Comments
 (0)