Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[COST-4175] Fix AWS first of the month issue #487

Merged
merged 13 commits into from
Mar 26, 2024
15 changes: 8 additions & 7 deletions nise/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -693,18 +693,19 @@ def _load_static_report_data(options):
end_dates = []
static_report_data = load_yaml(static_file)
for generator_dict in static_report_data.get("generators"):
for _, attributes in generator_dict.items():
for attributes in generator_dict.values():
start_date = get_start_date(attributes, options)
generated_start_date = calculate_start_date(start_date)
start_dates.append(generated_start_date)
if attributes.get("end_date"):
generated_end_date = calculate_end_date(generated_start_date, attributes.get("end_date"))
elif options.get("end_date") and options.get("end_date").date() != today().date():
generated_end_date = calculate_end_date(generated_start_date, options.get("end_date"))
else:
generated_end_date = today()

end_date = attributes.get("end_date", options.get("end_date"))
generated_end_date = today()
if end_date and end_date != today().date():
samdoran marked this conversation as resolved.
Show resolved Hide resolved
generated_end_date = calculate_end_date(generated_start_date, end_date)

if options.get("provider") == "azure":
generated_end_date += datetime.timedelta(hours=24)

end_dates.append(generated_end_date)

attributes["start_date"] = str(generated_start_date)
Expand Down
47 changes: 26 additions & 21 deletions nise/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,33 +501,39 @@ def _create_generator_dates_from_yaml(attributes, month):
gen_start_date = None
gen_end_date = None

start_date = attributes.get("start_date")
end_date = attributes.get("end_date")
month_start = month.get("start")
month_end = month.get("end")

# Use a different variable for the end of month comparison. This matters
# when the end_date is the same as the month_end, which can happen based
# on the specified --end-date parameter or on the first of the month.
month_end_compare = month_end
if (month_end.month, month_end.day) != (end_date.month, end_date.day):
samdoran marked this conversation as resolved.
Show resolved Hide resolved
# Create a new datetime object and store it, leaving the original
# month_end object unmodified.
month_end_compare = month_end_compare.replace(hour=23, minute=59, second=59)

# Generator range is larger then current month on both start and end
if attributes.get("start_date") < month.get("start") and attributes.get("end_date") > month.get("end").replace(
hour=23, minute=59, second=59
):
gen_start_date = month.get("start")
gen_end_date = month.get("end")
if start_date < month_start and end_date > month_end_compare:
gen_start_date = month_start
gen_end_date = month_end

# Generator starts before month start and ends within month
if attributes.get("start_date") <= month.get("start") and attributes.get("end_date") <= month.get("end").replace(
hour=23, minute=59, second=59
):
gen_start_date = month.get("start")
gen_end_date = attributes.get("end_date")
elif start_date <= month_start and end_date <= month_end_compare:
samdoran marked this conversation as resolved.
Show resolved Hide resolved
gen_start_date = month_start
gen_end_date = end_date

# Generator is within month
if attributes.get("start_date") >= month.get("start") and attributes.get("end_date") <= month.get("end").replace(
hour=23, minute=59, second=59
):
gen_start_date = attributes.get("start_date")
gen_end_date = attributes.get("end_date")
elif start_date >= month_start and end_date <= month_end_compare:
gen_start_date = start_date
gen_end_date = end_date

# Generator starts within month and ends in next month
if attributes.get("start_date") >= month.get("start") and attributes.get("end_date") > month.get("end").replace(
hour=23, minute=59, second=59
):
gen_start_date = attributes.get("start_date")
gen_end_date = month.get("end")
elif start_date >= month_start and end_date > month_end_compare:
gen_start_date = start_date
gen_end_date = month_end

return gen_start_date, gen_end_date

Expand Down Expand Up @@ -593,7 +599,6 @@ def aws_create_marketplace_report(options): # noqa: C901

def aws_create_report(options): # noqa: C901
"""Create a cost usage report file."""
data = []
start_date = options.get("start_date")
end_date = options.get("end_date")
aws_finalize_report = options.get("aws_finalize_report")
Expand Down
67 changes: 65 additions & 2 deletions tests/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ def test_write_manifest(self):
def test_create_generator_for_dates_from_yaml(self):
"""Test helper function for generating dates."""
month = {
"name": "June",
"start": datetime.datetime(2021, 6, 30, 0, 0),
"end": datetime.datetime(2021, 6, 30, 23, 59),
}
Expand All @@ -135,10 +134,74 @@ def test_create_generator_for_dates_from_yaml(self):
self.assertEqual(start_date, datetime.datetime(2021, 6, 30, 0, 0))
self.assertEqual(end_date, datetime.datetime(2021, 6, 30, 23, 59))

def test_create_generator_for_dates_from_yaml_within_month(self):
month = {
"start": datetime.datetime(2023, 5, 1, 0, 0),
"end": datetime.datetime(2023, 5, 31, 23, 59),
}

attributes = {
"start_date": datetime.datetime(2023, 5, 5, 0, 0),
"end_date": datetime.datetime(2023, 5, 15, 15, 0),
}

start_date, end_date = _create_generator_dates_from_yaml(attributes, month)

self.assertEqual(start_date, datetime.datetime(2023, 5, 5, 0, 0))
self.assertEqual(end_date, datetime.datetime(2023, 5, 15, 15, 0))

def test_create_generator_for_dates_from_yaml_within_month_before_month_start(self):
month = {
"start": datetime.datetime(2023, 5, 1, 0, 0),
"end": datetime.datetime(2023, 5, 31, 23, 59),
}

attributes = {
"start_date": datetime.datetime(2023, 4, 5, 0, 0),
"end_date": datetime.datetime(2023, 5, 15, 15, 0),
}

start_date, end_date = _create_generator_dates_from_yaml(attributes, month)

self.assertEqual(start_date, datetime.datetime(2023, 5, 1, 0, 0))
self.assertEqual(end_date, datetime.datetime(2023, 5, 15, 15, 0))

def test_create_generator_for_dates_from_yaml_within_month_ends_next_month(self):
month = {
"start": datetime.datetime(2023, 5, 1, 0, 0),
"end": datetime.datetime(2023, 5, 31, 23, 59),
}

attributes = {
"start_date": datetime.datetime(2023, 5, 5, 0, 0),
"end_date": datetime.datetime(2023, 8, 15, 15, 0),
}

start_date, end_date = _create_generator_dates_from_yaml(attributes, month)

self.assertEqual(start_date, datetime.datetime(2023, 5, 5, 0, 0))
self.assertEqual(end_date, datetime.datetime(2023, 5, 31, 23, 59))

def test_create_generator_for_dates_from_yaml_first_month(self):
"""Test that correct dates are generated on the first of the month"""
month = {
samdoran marked this conversation as resolved.
Show resolved Hide resolved
"start": datetime.datetime(2024, 2, 1, 0, 0, tzinfo=datetime.timezone.utc),
"end": datetime.datetime(2024, 3, 1, 0, 0, tzinfo=datetime.timezone.utc),
}

attributes = {
"start_date": datetime.datetime(2024, 2, 1, 0, 0, tzinfo=datetime.timezone.utc),
"end_date": datetime.datetime(2024, 3, 1, 23, 0, tzinfo=datetime.timezone.utc),
}

start_date, end_date = _create_generator_dates_from_yaml(attributes, month)

self.assertEqual(start_date, datetime.datetime(2024, 2, 1, 0, 0, tzinfo=datetime.timezone.utc))
self.assertEqual(end_date, datetime.datetime(2024, 3, 1, 0, 0, tzinfo=datetime.timezone.utc))

def test_create_generator_for_dates_from_yaml_middle_month(self):
"""Test helper function for generating dates verifying the middle month in a 3 month range."""
month = {
"name": "June",
"start": datetime.datetime(2021, 6, 30, 0, 0),
"end": datetime.datetime(2021, 6, 30, 23, 59),
}
Expand Down
Loading