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

aws-ce-grafana-backend: fix from/to edge cases #4865

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions helm-charts/aws-ce-grafana-backend/mounted-files/webserver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from datetime import date, datetime, timedelta, timezone
from datetime import datetime, timedelta, timezone

from flask import Flask, request

Expand All @@ -16,30 +16,41 @@

def _parse_from_to_in_query_params():
"""
Parse "from" and "to" query parameters, expected to arrive as YYYY-MM-DD
strings.

# FIXME: Avoid...
# botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the GetCostAndUsage operation: end date past the beginning of next month
Parse "from" and "to" query parameters, expected to be passed as YYYY-MM-DD
formatted strings or including time as well.

- "to" defaults to current date (UTC)
- "from" defaults to 30 days before what to is set to

Note that Python 3.11 is required to parse a datetime like
2024-07-27T15:50:18.231Z with a Z in the end, and that Grafana's
`${__from:date}` variable is UTC based, but as soon as its adjusted with a
custom format, it no longer is UTC based. Due to that, we need to be able to
parse the full datetime string.
"""
now_date = datetime.now(timezone.utc).date()
if request.args.get("to"):
to_dt = date.fromisoformat(request.args["to"])
to_date = datetime.fromisoformat(request.args["to"]).date()
else:
to_dt = datetime.now(timezone.utc).date()
to_date = now_date
if request.args.get("from"):
from_dt = date.fromisoformat(request.args["from"])
from_date = datetime.fromisoformat(request.args["from"]).date()
else:
from_dt = to_dt - timedelta(days=30)

# the end date gets excluded, so add one day to get it included
to_dt += timedelta(days=1)
from_date = to_date - timedelta(days=30)

# the to_date isn't included when declaring start/end dates against the AWS
# CE API, so we try to add one day to it to make it inclusive
to_date = to_date + timedelta(days=1)
# prevent "end date past the beginning of next month" errors
if to_date > now_date:
to_date = now_date
# prevent "Start date (and hour) should be before end date (and hour)"
if from_date >= now_date:
from_date = to_date - timedelta(days=1)

# format back to YYYY-MM-DD strings
from_date = from_dt.strftime("%Y-%m-%d")
to_date = to_dt.strftime("%Y-%m-%d")
from_date = from_date.strftime("%Y-%m-%d")
to_date = to_date.strftime("%Y-%m-%d")

return from_date, to_date

Expand Down