diff --git a/gnocchi/aggregates/moving_stats.py b/gnocchi/aggregates/moving_stats.py index 3645a0f3..cfd04adb 100644 --- a/gnocchi/aggregates/moving_stats.py +++ b/gnocchi/aggregates/moving_stats.py @@ -16,7 +16,6 @@ import datetime import numpy -from oslo_utils import strutils from oslo_utils import timeutils import pandas import six @@ -75,7 +74,7 @@ class MovingAverage(aggregates.CustomAggregator): """ if center: - center = strutils.bool_from_string(center) + center = utils.strtobool(center) def moving_window(x): msec = datetime.timedelta(milliseconds=1) diff --git a/gnocchi/rest/__init__.py b/gnocchi/rest/__init__.py index 9e64dfff..abef8b16 100644 --- a/gnocchi/rest/__init__.py +++ b/gnocchi/rest/__init__.py @@ -21,7 +21,6 @@ import uuid from concurrent import futures import jsonpatch from oslo_utils import dictutils -from oslo_utils import strutils import pecan from pecan import rest import pyparsing @@ -138,16 +137,8 @@ def Timespan(value): def get_header_option(name, params): type, options = werkzeug.http.parse_options_header( pecan.request.headers.get('Accept')) - try: - return strutils.bool_from_string( - options.get(name, params.pop(name, 'false')), - strict=True) - except ValueError as e: - method = 'Accept' if name in options else 'query' - abort( - 400, - "Unable to parse %s value in %s: %s" - % (name, method, six.text_type(e))) + return strtobool('Accept header' if name in options else name, + options.get(name, params.pop(name, 'false'))) def get_history(params): @@ -158,6 +149,17 @@ def get_details(params): return get_header_option('details', params) +def strtobool(varname, v): + """Convert a string to a boolean. + + Default to false if unable to convert. + """ + try: + return utils.strtobool(v) + except ValueError as e: + abort(400, "Unable to parse `%s': %s" % (varname, six.text_type(e))) + + RESOURCE_DEFAULT_PAGINATION = ['revision_start:asc', 'started_at:asc'] @@ -427,7 +429,7 @@ class MetricController(rest.RestController): except ValueError as e: abort(400, e) - if strutils.bool_from_string(refresh): + if strtobool("refresh", refresh): pecan.request.storage.process_new_measures( pecan.request.indexer, [six.text_type(self.metric.id)], True) @@ -1366,7 +1368,7 @@ class ResourcesMetricsMeasuresBatchController(rest.RestController): names=names, resource_id=resource_id) known_names = [m.name for m in metrics] - if strutils.bool_from_string(create_metrics): + if strtobool("create_metrics", create_metrics): already_exists_names = [] for name in names: if name not in known_names: @@ -1603,7 +1605,7 @@ class AggregationController(rest.RestController): abort(400, "fill must be a float or \'null\': %s" % e) try: - if strutils.bool_from_string(refresh): + if strtobool("refresh", refresh): pecan.request.storage.process_new_measures( pecan.request.indexer, [six.text_type(m.id) for m in metrics], True) @@ -1667,7 +1669,7 @@ class StatusController(rest.RestController): enforce("get status", {}) try: report = pecan.request.storage.incoming.measures_report( - strutils.bool_from_string(details)) + strtobool("details", details)) except incoming.ReportGenerationError: abort(503, 'Unable to generate status. Please retry.') report_dict = {"storage": {"summary": report['summary']}} diff --git a/gnocchi/storage/common/redis.py b/gnocchi/storage/common/redis.py index 54a5a350..91a90d4d 100644 --- a/gnocchi/storage/common/redis.py +++ b/gnocchi/storage/common/redis.py @@ -18,8 +18,6 @@ from __future__ import absolute_import from six.moves.urllib import parse -from oslo_utils import strutils - try: import redis from redis import sentinel @@ -27,6 +25,8 @@ except ImportError: redis = None sentinel = None +from gnocchi import utils + SEP = ':' @@ -96,7 +96,7 @@ def get_client(conf): if a not in options: continue if a in CLIENT_BOOL_ARGS: - v = strutils.bool_from_string(options[a][-1]) + v = utils.strtobool(options[a][-1]) elif a in CLIENT_LIST_ARGS: v = options[a][-1] elif a in CLIENT_INT_ARGS: diff --git a/gnocchi/tests/test_rest.py b/gnocchi/tests/test_rest.py index df1788ce..296755f4 100644 --- a/gnocchi/tests/test_rest.py +++ b/gnocchi/tests/test_rest.py @@ -1450,8 +1450,7 @@ class ResourceTest(RestTest): result = self.app.get("/v1/resource/generic?details=awesome", status=400) self.assertIn( - b"Unable to parse details value in query: " - b"Unrecognized value 'awesome', acceptable values are", + b"Unable to parse `details': invalid truth value", result.body) def test_list_resources_with_bad_details_in_accept(self): @@ -1461,8 +1460,7 @@ class ResourceTest(RestTest): }, status=400) self.assertIn( - b"Unable to parse details value in Accept: " - b"Unrecognized value 'foo', acceptable values are", + b"Unable to parse `Accept header': invalid truth value", result.body) def _do_test_list_resources_with_detail(self, request): diff --git a/gnocchi/utils.py b/gnocchi/utils.py index 45c4ccc9..816548de 100644 --- a/gnocchi/utils.py +++ b/gnocchi/utils.py @@ -1,5 +1,6 @@ # -*- encoding: utf-8 -*- # +# Copyright © 2015-2017 Red Hat, Inc. # Copyright © 2015-2016 eNovance # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -14,6 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. import datetime +import distutils.util import errno import itertools import multiprocessing @@ -206,3 +208,9 @@ def ensure_paths(paths): except OSError as e: if e.errno != errno.EEXIST: raise + + +def strtobool(v): + if isinstance(v, bool): + return v + return bool(distutils.util.strtobool(v))