Allow a user to submit start and end time as strings
get_compute_usage currently requires a user to provide a datetime object. That's actually fairly unfriendly. Also, it turns out if you happen to produce one of those with timezone offset information, Nova will return a 400 error. It's pretty easy to convert a datetime with timezone info to a datetime in UTC without it - so do that first. Now a user can submit a fully compliant ISO 8601 datetime with whatever info they want and we'll make it meet nova's standards. They can also supply a datetime if they prefer. Also - do date parsing before project get - to avoid an API call if the validation that doesn't need an API call fails. Finally, supply a default for 'start' of the first day OpenStack existed. Change-Id: I53989d47f0d24695c19c1023e35acb315bec9eea
This commit is contained in:
parent
12b07e12e2
commit
072001a628
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- get_compute_usage now has a default value for the start
|
||||||
|
parameter of 2010-07-06. That was the date the OpenStack
|
||||||
|
project started. It's completely impossible for someone
|
||||||
|
to have Nova usage data that goes back further in time.
|
||||||
|
Also, both the start and end date parameters now also
|
||||||
|
accept strings which will be parsed and timezones will
|
||||||
|
be properly converted to UTC which is what Nova expects.
|
@ -19,6 +19,7 @@ requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0
|
|||||||
requestsexceptions>=1.2.0 # Apache-2.0
|
requestsexceptions>=1.2.0 # Apache-2.0
|
||||||
six>=1.9.0 # MIT
|
six>=1.9.0 # MIT
|
||||||
futures>=3.0;python_version=='2.7' or python_version=='2.6' # BSD
|
futures>=3.0;python_version=='2.7' or python_version=='2.6' # BSD
|
||||||
|
iso8601>=0.1.11 # MIT
|
||||||
|
|
||||||
keystoneauth1>=2.20.0 # Apache-2.0
|
keystoneauth1>=2.20.0 # Apache-2.0
|
||||||
netifaces>=0.10.4 # MIT
|
netifaces>=0.10.4 # MIT
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import iso8601
|
||||||
import jsonpatch
|
import jsonpatch
|
||||||
|
|
||||||
from ironicclient import exceptions as ironic_exceptions
|
from ironicclient import exceptions as ironic_exceptions
|
||||||
@ -2103,22 +2104,60 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
|||||||
except nova_exceptions.BadRequest:
|
except nova_exceptions.BadRequest:
|
||||||
raise OpenStackCloudException("nova client call failed")
|
raise OpenStackCloudException("nova client call failed")
|
||||||
|
|
||||||
def get_compute_usage(self, name_or_id, start, end=None):
|
def get_compute_usage(self, name_or_id, start=None, end=None):
|
||||||
""" Get usage for a specific project
|
""" Get usage for a specific project
|
||||||
|
|
||||||
:param name_or_id: project name or id
|
:param name_or_id: project name or id
|
||||||
:param start: :class:`datetime.datetime` Start date in UTC
|
:param start: :class:`datetime.datetime` or string. Start date in UTC
|
||||||
:param end: :class:`datetime.datetime` End date in UTC. Defaults to now
|
Defaults to 2010-07-06T12:00:00Z (the date the OpenStack
|
||||||
|
project was started)
|
||||||
|
:param end: :class:`datetime.datetime` or string. End date in UTC.
|
||||||
|
Defaults to now
|
||||||
:raises: OpenStackCloudException if it's not a valid project
|
:raises: OpenStackCloudException if it's not a valid project
|
||||||
|
|
||||||
:returns: Munch object with the usage
|
:returns: Munch object with the usage
|
||||||
"""
|
"""
|
||||||
|
def parse_date(date):
|
||||||
|
try:
|
||||||
|
return iso8601.parse_date(date)
|
||||||
|
except iso8601.iso8601.ParseError:
|
||||||
|
# Yes. This is an exception mask. However,iso8601 is an
|
||||||
|
# implementation detail - and the error message is actually
|
||||||
|
# less informative.
|
||||||
|
raise OpenStackCloudException(
|
||||||
|
"Date given, {date}, is invalid. Please pass in a date"
|
||||||
|
" string in ISO 8601 format -"
|
||||||
|
" YYYY-MM-DDTHH:MM:SS".format(
|
||||||
|
date=date))
|
||||||
|
|
||||||
|
def parse_datetime_for_nova(date):
|
||||||
|
# Must strip tzinfo from the date- it breaks Nova. Also,
|
||||||
|
# Nova is expecting this in UTC. If someone passes in an
|
||||||
|
# ISO8601 date string or a datetime with timzeone data attached,
|
||||||
|
# strip the timezone data but apply offset math first so that
|
||||||
|
# the user's well formed perfectly valid date will be used
|
||||||
|
# correctly.
|
||||||
|
offset = date.utcoffset()
|
||||||
|
if offset:
|
||||||
|
date = date - datetime.timedelta(hours=offset)
|
||||||
|
return date.replace(tzinfo=None)
|
||||||
|
|
||||||
|
if not start:
|
||||||
|
start = parse_date('2010-07-06')
|
||||||
|
elif not isinstance(start, datetime.datetime):
|
||||||
|
start = parse_date(start)
|
||||||
|
if not end:
|
||||||
|
end = datetime.datetime.utcnow()
|
||||||
|
elif not isinstance(start, datetime.datetime):
|
||||||
|
end = parse_date(end)
|
||||||
|
|
||||||
|
start = parse_datetime_for_nova(start)
|
||||||
|
end = parse_datetime_for_nova(end)
|
||||||
|
|
||||||
proj = self.get_project(name_or_id)
|
proj = self.get_project(name_or_id)
|
||||||
if not proj:
|
if not proj:
|
||||||
raise OpenStackCloudException("project does not exist: {}".format(
|
raise OpenStackCloudException("project does not exist: {}".format(
|
||||||
name=proj.id))
|
name=proj.id))
|
||||||
if not end:
|
|
||||||
end = datetime.datetime.now()
|
|
||||||
|
|
||||||
with _utils.shade_exceptions(
|
with _utils.shade_exceptions(
|
||||||
"Unable to get resources usage for project: {name}".format(
|
"Unable to get resources usage for project: {name}".format(
|
||||||
|
Loading…
Reference in New Issue
Block a user